如何判断c++模板类型是否为C风格字符串
how to tell if a C++ template type is C-style string
我正试图写一个模板is_c_str
来测试类型是否为c风格字符串。我需要这作为尝试写一个to_string函数,如我在这里的另一个问题所示:STL容器迭代器的模板特化?
我需要区分c_str和其他类型的指针和迭代器,这样我就可以在表面值上表示第一个,并将指针/迭代器渲染为不透明的"itor"或"ptr"。代码如下:
#include <iostream>
template<class T>
struct is_c_str
: std::integral_constant<
bool,
!std::is_same<char *, typename std::remove_reference<typename std::remove_cv<T>::type>::type>::value
> {};
int main() {
auto sz = "Hello"; //Or: const char * sz = "Hello";
int i;
double d;
std::cout << is_c_str<decltype(sz)>::value << ", "
<< is_c_str<decltype(i)>::value << ", "
<< is_c_str<decltype(d)>::value << std::endl;
}
而is_c_str
不仅捕获const char *
,还捕获int
和double
。以上代码输出:
1, 1, 1
(自gcc-4.8.1起)。
我的问题是如何修复is_c_str
正确捕获c风格字符串?
您想要检查类型是否与char *
相同,但是您否定了std::is_same
的结果,这显然不会产生正确的结果。我们把它删掉
template<class T>
struct is_c_str
: std::integral_constant<
bool,
std::is_same<char *, typename std::remove_reference<typename std::remove_cv<T>::type>::type>::value
> {};
但是,这将导致输出0, 0, 0
。现在的问题是remove_cv
删除了顶级cv限定符,但char const *
中的const
不是顶级的。
如果您想同时匹配char *
和char const *
,最简单的解决方案是:
template<class T>
struct is_c_str
: std::integral_constant<
bool,
std::is_same<char *, typename std::remove_reference<typename std::remove_cv<T>::type>::type>::value ||
std::is_same<char const *, typename std::remove_reference<typename std::remove_cv<T>::type>::type>::value
> {};
以上版本仍然不匹配char[]
。如果你也想匹配它们,并减少std::remove_reference
和std::remove_cv
组合的冗长性,请使用std::decay
代替。
template<class T>
struct is_c_str
: std::integral_constant<
bool,
std::is_same<char const *, typename std::decay<T>::type>::value ||
std::is_same<char *, typename std::decay<T>::type>::value
> {};
我尝试了这个,它似乎工作:
#include <iostream>
template<class T>
struct is_c_str : std::integral_constant<bool, false> {};
template<>
struct is_c_str<char*> : std::integral_constant<bool, true> {};
template<>
struct is_c_str<const char*> : std::integral_constant<bool, true> {};
int main() {
auto sz = "Hello";
int i;
double d;
std::cout << is_c_str<decltype(sz)>::value << ", "
<< is_c_str<decltype(i)>::value << ", "
<< is_c_str<decltype(d)>::value << std::endl;
}
显然,列举每个情况不如将通用谓词放在std:integral_constant
中那么优雅,但另一方面,谓词对于像我这样的白痴来说是陌生的语言,而"蛮力"模板专门化在某种程度上更容易理解,并且在这种情况下可行,因为有很少的专门化。
sz
的类型是char const*
,但是std::remove_cv<>
只删除了顶层的const
,所以你不能通过它的应用得到char*
。相反,您可以在使用std::decay<>
:
char const*
:
namespace detail
{
template<class T>
struct is_c_str : std::is_same<char const*, T> {};
}
template<class T>
struct is_c_str : detail::is_c_str<typename std::decay<T>::type> {};
int main() {
auto sz = "Hello";
int i;
double d;
std::cout << is_c_str<decltype(sz)>::value << ", "
<< is_c_str<decltype(i)>::value << ", "
<< is_c_str<decltype(d)>::value << std::endl;
}
你也错误地否定了条件。
<<p> 生活例子/kbd>已经有了一些解决方案,但由于最简单的解决方案确实很简单,我将在这里草草写下来。
template< typename, typename = void >
struct is_c_str
: std::false_type {};
template< typename t >
struct is_c_str< t *,
typename std::enable_if< std::is_same<
typename std::decay< t >::type,
char
>::value >::type
>
: std::true_type {};
当然,棘手的部分是分析指针类型内部的内容,而不是指针类型本身。
有几个问题。
-
!std::is_same<char *, typename std::remove_reference<typename std::remove_cv<T>::type>::type>::value
必须是
std::is_same<char *, typename std::remove_reference<typename std::remove_cv<T>::type>::type>::value
-
您使用
typename std::remove_reference<typename std::remove_cv<T>::type>::type>::value
的逻辑有缺陷。它不会将char const*
转换为char*
。可将char* const
转换为char*
你需要的是:
template<class T>
struct is_c_str
: std::integral_constant<
bool,
std::is_same<char *, typename std::remove_reference<typename std::remove_cv<T>::type>::type>::value ||
std::is_same<char const*, typename std::remove_reference<typename std::remove_cv<T>::type>::type>::value
> {};
- 是否可以初始化不可复制类型的成员变量(或基类)
- 是否可以从int转换为enum类类型
- 检查 std::shared_ptr<> 的当前底层类型是否为 T
- 函数作为模板参数,是否对返回类型强制约束
- JS相等运算符(如===)是否可以使用embind类型
- visual是否可以在c++中创建一个接收无限数量相同类型(或至少相当数量)参数的函数
- 检查函数返回类型是否与STL容器类型值相同
- 在类型和包装器之间reinterpret_cast是否安全<Type>?
- 检查某些类型是否是模板类 std::optional 的实例化
- 是否有内置方法可以强制转换为不同的基础类型,但保留常量限定符?
- C++类型特征,以查看是否可以<uint32_t>对类型"K"的任何变量调用"static_cast(k)"
- boost 是否有按特殊类型值编码状态"compact optional"?
- 初始值设定项列表是否只接受使用相同类型的值初始化变量?
- 是否有任何建议来统一函数类型限定符并简化可恶的函数类型?
- 表达式 SFINAE:如何根据类型是否包含具有一个或多个参数的函数来选择模板版本
- 检查一个类型是否直接派生自"enable if"上下文中的另一个类型(是其子类型)
- 在运行时检查继承是否只有一种类型和 void*
- 给定一个C++嵌套的私有结构类型,是否有从文件范围静态函数访问它的策略
- 将类型声明为类型模板参数的模板参数的一部分是否合法?
- 当返回类型声明为 ListNode 时,我们是否可以返回 false<T>*