简体   繁体   English

为什么声明顺序对于将成员函数指针作为模板参数传递很重要?

[英]Why is declaration order important for passing a member function pointer as a template argument?

Look at this code: 看看这段代码:

template <typename T, void (T::*pfn)()> struct Testee {};

class Tester
{
private:
    void foo() {}
public:
    using type_t = Testee<Tester, &Tester::foo>;    
};

It successfully compiles with g++ -std=c++14 -Wall -Wextra . 它成功地用g++ -std=c++14 -Wall -Wextra

However, when I change the order of foo and type_t , an error occurs: 但是,当我更改footype_t的顺序时,会发生错误:

$ cat test.cpp
template <typename T, void (T::*pfn)()> struct Testee {};

class Tester
{
public:
    using type_t = Testee<Tester, &Tester::foo>;
private:
    void foo() {}
};

int main()
{
}

$ g++ -std=c++14 -Wall -Wextra -pedantic test.cpp
test.cpp:6:36: error: incomplete type ‘Tester’ used in nested name specifier
     using type_t = Testee<Tester, &Tester::foo>;
                                    ^
test.cpp:6:47: error: template argument 2 is invalid
     using type_t = Testee<Tester, &Tester::foo>;
                                               ^

Usually, the order of declarations in class definitions has no effect on name resolving. 通常,类定义中的声明顺序对名称解析没有影响。 For example: 例如:

struct A // OK
{
    void foo(int a = val) { }
    static constexpr const int val = 42;
};

struct B // OK
{
    static constexpr const int val = 42;
    void foo(int a = val) { }
};

However, it has an effect in this case. 但是,它在这种情况下有效。 Why? 为什么?

This is not really related to templates. 这与模板无关。 You get a similar error on: 你得到一个类似的错误

class Tester
{
public:
    using type_t = decltype(&Tester::foo);
private:
    void foo() {}
};

It's true that a class is (Standard 9.2/2): 一个类确实是(标准9.2 / 2):

regarded as complete within function bodies, default arguments, using-declarations introducing inheriting constructors (12.9), exception-specifications , and brace-or-equal-initializers for non-static data members (including such things in nested classes). 在函数体,默认参数,引用继承构造函数(12.9)的使用声明异常规范和非静态数据成员的括号或等于初始化器 (包括嵌套类中的这类事物)中被认为是完整的。

However, the definition of a member type is not in that list, so it can only use names declared before that point. 但是,成员类型的定义不在该列表中,因此它只能使用在该点之前声明的名称。

Usually, the order of declaration in class definition have no effects. 通常,类定义中的声明顺序没有效果。

That's quite an overstatement. 这是夸大其词。 A few uses of declarations that appear later in the class definition are allowed, to the best of my knowledge: 根据我的知识,允许在类定义中稍后出现的一些声明用法:

  • default arguments (as you mentioned; but not default template arguments) 默认参数(如您所述;但不是默认模板参数)
  • uses within a function body, function-try-block or member initializer 在函数体,function-try-block或成员初始化器中使用
  • in-class initializers (C++11 or later) 类内初始化器(C ++ 11或更高版本)

Also, as has been mentioned, the order of data members affects construction and destruction order. 而且,如上所述,数据成员的顺序影响构造和销毁顺序。 Also, reordering stuff between translation units may surprisingly cause an ODR violation. 此外,翻译单元之间的重新排序可能会令人惊讶地导致ODR违规。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM