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

ikh*_*ikh 23 c++ templates member-pointers

看看这段代码:

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

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

它成功编译g++ -std=c++14 -Wall -Wextra.

但是,当我改变的顺序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>;
                                               ^
Run Code Online (Sandbox Code Playgroud)

通常,类定义中的声明顺序对名称解析没有影响.例如:

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

但是,它在这种情况下有效.为什么?

asc*_*ler 33

这与模板无关.你得到一个类似的错误:

class Tester
{
public:
    using type_t = decltype(&Tester::foo);
private:
    void foo() {}
};
Run Code Online (Sandbox Code Playgroud)

一个类确实是(标准9.2/2):

视为功能体,默认参数内完成,使用-声明引入继承构造(12.9),例外的规范,和 支架-或等于-初始化用于非静态数据成员(包括嵌套类这样的事情).

但是,成员类型的定义不在该列表中,因此它只能使用在该点之前声明的名称.

  • @ikh你可能总是改变你的选择.但这证明了为什么在接受答案之前等待一段时间是个好主意,以防出现更好的答案.这是正确的答案.速度和正确性并不总是相关的.接受错误的答案会给将来阅读此页面的人造成混淆. (7认同)