我在函数中定义的结构中定义了静态函数。我想获得一个指向内部函数的模板函数指针。
考虑以下示例:
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
答案 0 :(得分:2)
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_in
和generator_in::get_token
都没有链接。
最后:[basic.link]/2.3:
-名称没有链接时,表示的实体不能被其他作用域中的名称引用。