Определяет ли стандарт C ++, должны ли функциональные определения функций-членов в структурах иметь статическую связь? - PullRequest
0 голосов
/ 06 июля 2018

У меня есть статическая функция, определенная в структуре, определенной внутри функции. Я хочу получить указатель функции шаблона на внутреннюю функцию.

Рассмотрим следующий пример:

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, а также с компилятором clang 6.0 и gcc 8.1 на wandbox.org. MSVC и clang работают, gcc - нет.

Кто прав? Clang и msvc слишком просты и не соответствуют стандарту c ++ или gcc просто еще не реализовал это? (Или это может быть даже ошибка?) Что стандарт говорит об этом?

EDIT : Сообщение об ошибке от 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

1 Ответ

0 голосов
/ 06 июля 2018

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:

* +1032 * & mdash; Когда у имени нет связи , обозначаемое им лицо не может быть упомянуто именами из других областей.
...