【问题标题】:Does the C++ standard define if in-function definitions of member functions in structs must have static linkage?C++ 标准是否定义了结构中成员函数的函数内定义是否必须具有静态链接?
【发布时间】:2018-12-15 00:17:01
【问题描述】:

我在函数中定义的结构中定义了一个静态函数。我想得到一个指向内部函数的模板函数指针。

考虑以下示例:

template <class Func, Func GetToken>
struct token_user {
    void foo () { GetToken(); } // Do something with token.
};

struct generator_out {
    constexpr static const auto get_token() {return 0;}
};

int main() {
    struct generator_in {
        constexpr static const auto get_token() {return 0;}
    };
    // Works fine
    token_user<decltype(&generator_out::get_token), &generator_out::get_token>(); 
    // Fails with GCC, works with clang and msvc
    token_user<decltype(&generator_in::get_token), &generator_in::get_token>();
}

我使用本地 MSVC 2017 编译器以及 wandbox.org 上的 clang 6.0 和 gcc 8.1 编译器对此进行了测试。 MSVC 和 clang 可以工作,gcc 不行。

谁是正确的? clang 和 msvc 是否过于宽容并弯曲了 c++ 标准,或者 gcc 还没有实现这一点? (或者它甚至可能是一个错误?)标准对此有何评论?

编辑: 来自 gcc 的错误消息:

prog.cc: In function 'int main()':
prog.cc:15:76: error: 'main()::generator_in::get_token' is not a valid template argument for type 'const int (*)()' because 'static constexpr const auto main()::generator_in::get_token()' has no linkage
 token_user<decltype(&generator_in::get_token), &generator_in::get_token>(); // Fails with GCC, works with clang and msvc

【问题讨论】:

  • @OlivierSohn 说明符的顺序无关紧要,只是个人喜好问题。
  • @VTT 我不确定这是否是一个错误。可能是 msvc 和 clang 只支持实验性功能。
  • @C.Esch 如果 gcc 打印 error: 是一个错误。标准还定义了函数内定义没有链接,但我不确定为什么它会阻止 gcc 使用指向函数的指针作为模板参数。
  • 可能链接到this
  • clang 6.0 的错误也是std std=c++17时没问题

标签: c++ gcc visual-c++ clang language-lawyer


【解决方案1】:

GCC 是对的,generator_in::get_token 没有链接,不能在声明的范围之外使用,因此不能用作实例化token_user 的参数。

[basic.link]/8 和 /9(我只包括相关部分):

...除非另有说明,在块范围内声明的名称没有链接。

例子:

void f() {
  struct A { int x; };  // no linkage
}

这很重要,因为成员函数具有类的链接。 [basic.link]/5:

... 成员函数、静态数据成员、类范围的命名类或枚举,或在类范围 typedef 声明中定义的未命名类或枚举,以便类或枚举具有用于链接目的的 typedef 名称([dcl.typedef]),如果有的话,与它所属的类的名称具有相同的链接。

所以generator_ingenerator_in::get_token 都没有链接。

最后:[basic.link]/2.3:

——当一个名称​​没有链接时,它所表示的实体不能被其他范围的名称引用。

【讨论】:

  • 感谢您解决此问题。我有点惊讶这实际上是这样的。你知道有什么改变这个的计划吗?当它显然不是标准时,两个编译器实现它似乎很奇怪。
  • 还有一件事。在第 8 点它说except as noted。这还指哪些注释?那些在第 9 点?在这种情况下,我会问一个函数是否不属于compound type 异常。
猜你喜欢
  • 2012-03-14
  • 2013-12-31
  • 1970-01-01
  • 2021-01-10
  • 1970-01-01
  • 1970-01-01
  • 2019-01-31
  • 1970-01-01
  • 2012-06-14
相关资源
最近更新 更多