使用来自元函数的typedef声明成员函数

Que*_*tin 7 c++ language-lawyer c++17

请考虑以下代码:

template <class>
struct Foo_s {
    using type = void();
};

template <class>
using Foo_u = void();

template <class T>
struct Bar {
             Foo_u<void>       foo1; // OK
    typename Foo_s<void>::type foo2; // OK
             Foo_u<T>          foo3; // OK
    typename Foo_s<T>::type    foo4; // Boom.
};

template struct Bar<void>;
Run Code Online (Sandbox Code Playgroud)

foo4GCC 7.2,Clang 5.0.0和MSVC 19.10.25017 的失败声明.

GCC:

<source>: In instantiation of 'struct Bar<void>':
18 : <source>:18:17:   required from here
15 : <source>:15:29: error: field 'Bar<void>::foo4' invalidly declared function type
     typename Foo_s<T>::type foo4;
                             ^~~~
Run Code Online (Sandbox Code Playgroud)

铛:

15 : <source>:15:29: error: data member instantiated with function type 'typename Foo_s<void>::type' (aka 'void ()')
    typename Foo_s<T>::type foo4;
                            ^
18 : <source>:18:17: note: in instantiation of template class 'Bar<void>' requested here
template struct Bar<void>;
                ^
Run Code Online (Sandbox Code Playgroud)

MSVC:

15 : <source>(15): error C2207: 'Bar<T>::foo4': a member of a class template cannot acquire a function type
18 : <source>(18): note: see reference to class template instantiation 'Bar<void>' being compiled
Run Code Online (Sandbox Code Playgroud)

所有这些人似乎都认为我试图用函数类型声明一个数据成员.如您所见,这仅在类型嵌套(不是using模板)时发生,并且依赖于类的参数.这看起来像一个错误,但事实上,这三个编译器都同意这一点让我怀疑.

这是标准行为吗?如果是这样,是否有理由不允许这样做,有没有办法声明一个成员函数,其类型是用元程序计算的?

Col*_*mbo 4

[温度规格]/8 :

如果函数声明通过依赖类型获取其函数类型而不使用函数声明符的语法形式,则该程序是格式错误的。

这使得你的最后一行明显格式错误。这是有道理的,因为与其他依赖构造的情况一样,我们不希望短语的含义过于强烈地依赖于模板参数。

然而,[dcl.fct]/13

函数类型的 typedef 可用于声明函数,但不得用于定义函数。

这使得你的前三行格式良好——前两行是直接的,对于第三行,请注意

template-id引用别名模板的特化时,它相当于用其template-argument替换别名模板的type-id中的template-parameter获得的关联类型。

通过[temp.alias]