如何判断C++模板类型是否为C风格的字符串

tin*_*lyx 21 c++ templates type-traits c++11

我正在尝试编写一个模板is_c_str来测试一个类型是否是一个c风格的字符串.我需要这个尝试编写一个to_string函数,如我在这里的另一个问题所示: STL容器迭代器的模板特化?.

我需要分开c_str和其他类型的指针和迭代器,以便我可以在face值处表示第一个,并将指针/迭代器渲染为不透明的"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;
}
Run Code Online (Sandbox Code Playgroud)

然而,is_c_str仅捕获没有const char *,还intdouble.以上代码输出:

1, 1, 1
Run Code Online (Sandbox Code Playgroud)

(截至gcc-4.8.1).

我的问题是如何修复is_c_str以正确捕获C风格的字符串?

Pra*_*ian 20

你想检查类型是否与a相同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
> {};
Run Code Online (Sandbox Code Playgroud)

但是,现在这将导致输出0, 0, 0.现在的问题是remove_cv删除顶级cv限定符,但constin 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
> {};
Run Code Online (Sandbox Code Playgroud)

以上版本仍然不匹配char[].如果你想匹配这些呢,降低组合的详细程度std::remove_referencestd::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
> {};
Run Code Online (Sandbox Code Playgroud)


gpe*_*che 9

我试过这个似乎工作:

#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;
}
Run Code Online (Sandbox Code Playgroud)

显然列举每个案例并不像把一般谓词列入其中那么优雅std:integral_constant,但另一方面,谓词对于像我这样的白痴来说是外来语言,而"蛮力"模板专业化在某种程度上更易于理解,并且在这种情况下可行很少有专业.


0x4*_*2D2 8

类型szchar 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;
}
Run Code Online (Sandbox Code Playgroud)

你也错误地否定了这种情况.我也解决了这个问题.

Live Example


R S*_*ahu 2

有几个问题。

  1. 线路

    !std::is_same<char *, typename std::remove_reference<typename std::remove_cv<T>::type>::type>::value
    
    Run Code Online (Sandbox Code Playgroud)

    需要是

    std::is_same<char *, typename std::remove_reference<typename std::remove_cv<T>::type>::type>::value
    
    Run Code Online (Sandbox Code Playgroud)
  2. 你的使用逻辑typename std::remove_reference<typename std::remove_cv<T>::type>::type>::value有缺陷。它不会转换char const*char*. 它可以转换char* constchar*.

你需要的是:

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
> {};
Run Code Online (Sandbox Code Playgroud)