【问题标题】:Why is declaration order important for passing a member function pointer as a template argument?为什么声明顺序对于将成员函数指针作为模板参数传递很重要?
【发布时间】:2017-11-11 08:55:18
【问题描述】:

看看这段代码:

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

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

它使用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>;
                                               ^

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

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) { }
};

但是,它在这种情况下会产生影响。为什么?

【问题讨论】:

  • 你试过不同的编译器吗?
  • “类定义中的声明顺序没有影响”afaik 这通常不是真的,例如。成员按照声明的顺序构造
  • @tobi303 在这种情况下没有构造(即根本没有调用 ctor)
  • @LucaCappa 我知道,我只是说一般来说这个说法是不正确的
  • @max 嗯,我在coliru 中尝试过clang++,效果一样。

标签: c++ templates member-pointers


【解决方案1】:

通常,类定义中的声明顺序没有影响。

这有点夸大其词了。据我所知,允许在类定义后面出现一些声明:

  • 默认参数(如您所述;但不是默认模板参数)
  • 在函数体、函数尝试块或成员初始化器中使用
  • 类内初始化程序(C++11 或更高版本)

此外,如前所述,数据成员的顺序会影响构造和销毁顺序。此外,在翻译单元之间重新排序内容可能会导致 ODR 违规。

【讨论】:

    【解决方案2】:

    这实际上与模板无关。你会得到一个类似的error

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

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

    在函数体中被认为是完整的, 默认参数,using-declarations 引入继承构造函数 (12.9),exception-specifications,以及 brace-or-equal-initializers 用于非静态数据成员(包括嵌套类中的此类内容)。

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

    【讨论】:

    • 我喜欢这个答案,因为另一个例子和标准引用。如果你速度快,我会选择这个
    • @ikh 你可以随时改变你的选择。但这说明了为什么在接受答案之前等待一段时间是个好主意,以防出现更好的答案。这是正确的答案。速度和正确性并不总是相关的。接受不正确的答案会给以后阅读此页面的人造成混乱。
    猜你喜欢
    • 1970-01-01
    • 2010-12-25
    • 2020-10-26
    • 1970-01-01
    • 2017-03-17
    • 1970-01-01
    • 2011-05-24
    • 1970-01-01
    • 2022-01-06
    相关资源
    最近更新 更多