提问人:thor 提问时间:7/21/2014 最后编辑:Communitythor 更新时间:8/2/2014 访问量:4457
如何判断 C++ 模板类型是否为 C 样式字符串
how to tell if a C++ template type is C-style string
问:
我正在尝试编写一个模板来测试类型是否是 c 样式字符串。我需要它来尝试编写一个to_string函数,如我在这里的另一个问题所示:STL 容器迭代器的模板专用化?。is_c_str
我需要区分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)。
我的问题是如何修复以正确捕获 c 样式的字符串?is_c_str
答:
有几个问题。
线
!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
> {};
你想检查类型是否与 相同,但你否定了 的结果,这显然不会产生正确的结果。因此,让我们删除它。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
> {};
但是,这现在将导致 输出 .现在的问题是,remove_cv
删除了顶级 cv 限定符,但 in 不是顶级的。0, 0, 0
const
char 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
> {};
以上版本仍然不匹配。如果您也想匹配这些,并减少组合 和 的冗长程度,请改用 std::d ecay
。char[]
std::remove_reference
std::remove_cv
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
> {};
评论
std::decay_t
类型是 ,但只删除了顶级 ,因此无法通过其应用程序。相反,您可以在完全分解类型后检查:sz
char const*
std::remove_cv<>
const
char*
char const*
std::decay<>
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;
}
你也错误地否定了这个条件。我也解决了这个问题。
评论
sz
const char *
auto
我试过了这个,它似乎有效:
#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
评论
wchar_t
char
unsigned char
char16_t
char32_t
std::is_character_type
已经有一些解决方案,但由于最简单的解决方案非常简单,我将在这里记下它。
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 {};
当然,棘手的部分是分析指针类型内部的内容,而不是指针类型本身。
评论
remove_reference<remove_cv<int>>
char *
char*
char
wchar_t
char16_t
char32_t
template<class T> to_string(T * str);
std::decay_t<T>
char
wchar_t
char16_t
char32_t