String Literal的模板参数演绎

时间:2017-02-23 13:21:03

标签: c++ c++11 templates string-literals perfect-forwarding

我目前正在考虑如何最好地将通用类型的模板约束到std::sting以及字符串文字。因此,我使用std::is_same将推导出的类型与所需类型进行比较。在std::string的情况下,这可以立即使用。对于字符串文字,意思是char const数组,它仅在我对类型使用std::decay时才有效,然后将结果与类型char const *进行比较。如果我直接将推导出的类型与我认为的类型进行比较,is_same将返回false,如下面的示例代码所示。

template <class TYPE>
void function(TYPE&& parameter)
{
  //this doesn't work as expected
  std::cout << typeid(TYPE).name() << " : " << typeid(char const [5]).name() << std::endl;
  std::cout << std::is_same<char const [5], TYPE>::value << std::endl;
  //this works as expected
  std::cout << typeid(std::decay_t<TYPE>).name() << " : " << typeid(char const *).name() << std::endl;
  std::cout << std::is_same<char const *, std::decay_t<TYPE>>::value << std::endl;
}

int main(int argc, char** argv)
{
  function("name");
  return 0;
}

生成的输出如下:

char const [5] : char const [5]
0
char const * __ptr64 : char const * __ptr64
1

现在,我想知道为什么is_same在第一种情况下返回false,即使类型看起来相同。

我能想到的唯一可能的解释是,在函数std::is_same中,类似于std::decay的转换应用于类型(例如函数调用)。但是,这种转变也会发生在另一种类型中,产生相同的结果,从而导致平等。

2 个答案:

答案 0 :(得分:6)

字符串文字的值不是char const [N],而是引用 char const (&)[N]

这适用于我:

std::cout << std::is_same<char const (&)[5], TYPE>::value << std::endl;

注意here

  

1)指代表示类型类型的std::type_info对象。 如果type是引用类型,则结果引用表示引用类型的std::type_info对象

您可以像is_same一样轻松验证type_info不会丢弃引用,例如通过检查

std::is_same<int&, int>::value == false

这解释了为什么typeid名称相同,但您的is_same测试仍然失败。

答案 1 :(得分:2)

使用gcc自定义功能:

template < class T >
constexpr std::string type_name()
{
    std::string p = __PRETTY_FUNCTION__;
    return p.substr( 43 + 10, p.length() - 100 - 1 - 10 );
}

并将其添加到您的代码中:

std::cout << type_name<TYPE>() << " : " << type_name<char const [5]>() << std::endl;

结果是:

A5_c : A5_c
0
const char (&)[5] : const char [5]

因此,您需要在std::remove_reference上使用TYPE