为什么`typename`仍然是必要的,即使模板类型被声明为`class`?

时间:2013-10-15 02:26:24

标签: c++ templates compiler-errors typename type-deduction

#include <type_traits>

using namespace std;

template<class T> struct IsCharType          { enum { value = false }; };    
template<>        struct IsCharType<char>    { enum { value = true }; };    
template<>        struct IsCharType<wchar_t> { enum { value = true }; };

template<class CharType, class = enable_if<IsCharType<CharType>::value>::type>
struct MyString
{
    MyString()
    {}

    MyString(CharType*)
    {}
};

template<class CharType>
MyString<CharType> GetMyString(CharType* str) // error C2923
{
    return MyString<CharType>(str);
}

int main()
{}

我的编译器是VC ++ 2013 RC。由于C2923错误,无法编译上面的代码。

  

错误C2923:'MyString':   'std :: enable_if :: value,void&gt; :: type'无效   参数''

的模板类型参数

但是,如果我改变

template<class CharType, class = enable_if<IsCharType<CharType>::value>::type>

template<class CharType, class = typename enable_if<IsCharType<CharType>::value>::type>

然后就可以了。

我只是想知道为什么typename在这里是必要的?在这种情况下,我有两个原因:

  1. 编译器可以推断第二个模板参数是否是类型名称;因为我将其标记为class

  2. 即使编译器无法推断出它是否是类型名称,根据SFINAE规则,编译器也不会失败,因为未调用模板函数GetMyString

1 个答案:

答案 0 :(得分:1)

您尚未将其声明为类。您的模板参数声明

class = enable_if<IsCharType<CharType>::value>::type

是未命名类型参数的声明。我们可以给这个参数一个明确的名称,例如

class U = enable_if<IsCharType<CharType>::value>::type

所以在这种情况下,U被声明为类型参数(“as class”)。

同时,=右侧的所有内容都不是“声明为类”。它由编译器根据一般规则解释,而不考虑它碰巧是类型参数的默认参数。

逻辑如“因为这是类型参数的默认参数,编译器必须自己意识到这是一种类型”这里不适用仅仅因为语言规范没有说它适用。而且,语言标准实际上是说

  

模板声明或定义中使用的名称,即   取决于模板参数,假定不命名类型,除非   适用的名称查找查找类型名称或名称是合格的   通过关键字typename。

这意味着编译器需要假设

enable_if<IsCharType<CharType>::value>::type

不是类型,这与您的预期相反。

该语言确实有许多上下文,其中无条件地假定依赖名称来命名类型。这包括构造函数初始化列表,基类说明符和详细的类型说明符。但模板类型参数的默认参数不是这种上下文之一。

SFINAE不保存这里的情况。顾名思义,SFINAE在替代时起作用。你的代码永远不会被替换,它会更早地破坏。它只是一个无效的模板定义。