代码之家  ›  专栏  ›  技术社区  ›  Quentin

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

  •  7
  • Quentin  · 技术社区  · 8 年前

    考虑以下代码:

    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上失败。

    通用条款:

    <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 模板),并取决于类的参数。这看起来像一个bug,但这三个编译器都同意这一点,这一事实让我怀疑。

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

    1 回复  |  直到 8 年前
        1
  •  4
  •   Columbo    8 年前

    [temp.spec]/8 :

    如果函数声明通过依赖类型获得其函数类型,而不使用函数声明器的语法形式,则程序的格式不正确。

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

    然而 [dcl.fct]/13 :

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

    这使前三行的格式良好——前两行直接,第三行注意

    模板id 指别名模板的专门化, 它等价于通过替换 它的 模板参数 s代表 模板参数 s在 类型id 属于 别名模板。

    通过 [temp.alias] .