2017-02-23 27 views
6

我目前正在考虑如何最佳约束模板的通用类型到std::sting以及字符串文字。因此,我使用std::is_same将推导出的类型与期望的类型进行比较。在std::string的情况下,这个工作马上。对于一个字符串字面值,意思是一个字符常量数组,它只在我使用该类型的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返回在第一种情况下假,即使类型似乎是相同的。

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

+0

等到C++ 17,然后编写模板以使用'std :: string_view'。 –

+1

尝试从'TYPE'中移除参考。字符串文字是左值。 –

+0

谢谢你,你是对的。我不知道。将行更改为'std :: is_same > :: value'会导致相等。为什么字符串文字被认为是左值?如果它是一个整型文字,而不是它将被视为一个右值,不是吗?我们可以让这个被接受的答案吗? – user1488118

回答

6

字符串文本不通过值传递作为char const [N],但通过参考作为char const (&)[N]

这正常工作对我来说:

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

注意here

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

您可以轻松验证is_same不通过检查以同样的方式丢弃参考岬作为type_info,例如该

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

这就解释了为什么typeid名字是一样的,但你的is_same测试仍然失败。

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] 

所以,你需要在TYPE使用std::remove_reference

+0

我认为你是正确的影响。然而,Kerrek SB在评论中提到了这个原因:字符串文字显然是左值,而不是右值。因此,当通过转发参考参数传递时,类型被推断为'T'而不是'T'。 – user1488118

+0

@ user1488118当您在代码中使用相同的字符串文字时,例如在不同的地方使用'“string”'时,它实际上是相同的字符串。每次都不是新临时的,但是只要程序正在运行,它就会保留在内存中,所以当你引用它的时候,你实际上是用l值引用来引用它的。 – xinaiz

0

这可能是编译器的错误。编译器在编译时生成由typeid给出的类型对象。编译器不会为每个长度(0到2 ** n)编译数组类型,因此它会在需要时编译它们,并且可能会“忘记”重复。尝试使用一个特殊的模板来分隔包含类型的长度。这不是类型,但可以检查它是否与另一个相同。

template<class T, size_t size> 
struct array_t{}; 

    template <class T, size_t size> 
void function(T[size] parameter) { 
    std::cout << typeid(array_t<T, size>).name() << " : " << typeid(array_t<char, 5>).name() << std::endl; 
    std::cout << std::is_same<array_t<T, size>, array_t<char, 5>>::value << std::endl; 
};