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

bar*_*top 3 c++ language-lawyer

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

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

template <class T, class T::value_type>
void foo() { }
Run Code Online (Sandbox Code Playgroud)

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

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

Rak*_*111 5

正如评论中所提到的,它是一个精心设计的类型说明符.最佳解释一个例子:

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

实质上,您可以将它们(struct/class,enum)视为更受限制的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() { }
Run Code Online (Sandbox Code Playgroud)

当你有一个具有相同名称的类型和变量时需要它,或者当你有一个从属名称时指定它是什么(即class T::value_type,value_type是一个类,没有class之前的,它将是一个值.通常, a typename被使用.)

我不能提出范围运算符可能是参数名称的一部分的任何情况

你在这里只考虑类型模板参数; 非类型模板参数可以很好地使用范围运算符来命名类型.