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

时间:2017-11-24 13:06:15

标签: 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>;

foo4的声明在GCC 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;
                             ^~~~

锵:

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>;
                ^

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

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

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

1 个答案:

答案 0 :(得分:4)

[temp.spec]/8

  

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

这使你的最后一行显然格格不入。这是有道理的,因为在其他依赖构造的情况下,我们不希望短语的含义过于依赖模板参数。

然而,[dcl.fct]/13

  

函数类型的typedef可用于声明函数但应该   不能用于定义函数。

这使你的前三行格式正确 - 前两行直接,而第三行,请注意

  

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

[temp.alias]