Вызов функции шаблона друга без определения параметра в шаблоне класса

Я экспериментировал с вызовом шаблонной функции друга без параметра, который определен в шаблоне класса. Я не нашел решения именно для этого случая и решил свою проблему другим путем, но во время своих экспериментов я неожиданно нашел какой-то интересный фрагмент кода. Это работает, но я не знаю почему. Вот этот пример:

#include <iostream>

template<class T> class A
{
public:
        void test() const
        {
                std::cout << "A!" << std::endl;
        }

        template<class U> friend A fun()
        {
                return A();
        }
};

int main(int argc, char* argv[])
{
        A<double> aa; // 1
        const auto& a = fun<int>();

        a.test();

        return 0;
}

Как я уже сказал, это работает для меня на GCC 4.8.1. Если я удалю (1), произойдет сбой со следующим:

main.cpp: In function 'int main(int, char**)':                                                                                                                                                                     
main.cpp:20:18: error: 'fun' was not declared in this scope                                                                                                                                                        
  const auto& a = fun<int>();                                                                                                                                                                                      
                  ^                                                                                                                                                                                                
main.cpp:20:22: error: expected primary-expression before 'int'                                                                                                                                                    
  const auto& a = fun<int>();

Я подозреваю, что здесь есть UB, но будет очень интересно, если кто-нибудь сможет уточнить:

  1. Почему это вообще работает, пока я не сказал fun (), какую специализацию A он должен использовать?
  2. Если это не UB, какой тип T? Я попробовал type_info и обнаружил, что он не является ни int, ни double. typeid (). name () не помогло, так как оно возвращает 'FdvE' для меня.

1 ответ

Решение

Это похоже на ошибку GCC. friend Шаблоны функций, которые определены в классе, могут быть найдены только через ADL: GCC, очевидно, считает, aa во время ADL для звонка в main (без причины) и звонки A<double>"s fun, что подтверждается этим статическим утверждением:

void test() const
{
    static_assert( std::is_same<T, double>::value, "" );
}

Демо
Clang не компилирует этот код вообще.

Другие вопросы по тегам