为什么模板参数中的双冒号有效?

时间:2018-09-28 07:04:54

标签: c++ language-lawyer

在回答一个问题时,我遇到了这样的代码:

template<class T, class... Ts> void foo();

template <class T, class T::value_type>
void foo() { }

它以专用于foo模板函数的代码的形式出现,这是不对的,但这不是我的问题。我想知道为什么编译器允许这样的构造:class T::value_type在template参数中。我的意思是,这很明显是错误的,我无法提出范围运算符可能是参数名称(模板或函数)一部分的任何情况。因此,我有两个问题:

  1. 标准允许吗?还是编译器忽略了它?
  2. 如果标准允许,为什么会这样?有用例吗?

1 个答案:

答案 0 :(得分:5)

如评论中所述,它是elaborated type specifier。最好用一个例子来解释:

int main() {
    struct foo {}; // ok
    int foo = 0; // ok

    int test = foo; // ok, refers to variable 'foo'
    foo a; // error, 'foo' refers to variable
    struct foo b; // ok, 'struct' means that name lookup searches for classes only
}

从本质上讲,您可以将它们(struct/classenum)视为限制更严格的typename,因为它们分别只允许类或枚举。另请注意,您的原始示例中允许使用typename

template<class T, class... Ts> void foo();

template <class T, typename T::value_type> // Ok, value_type needs to be a type
//                 ^^^^^^^^^^^^^^^^^^^^^^^ it's a non-type template parameter
void foo() { }

当类型和变量具有相同的名称时,或者在您具有从属名称时(例如,在class T::value_type中,value_type是类,之前没有class的话,它应该是一个值。通常使用typename。)

  

我无法想到范围运算符可能是参数名称的一部分的任何情况

您在这里只想到类型模板参数;非类型模板参数可以很好地使用范围运算符来命名类型。