Разрешение имён при определении пользовательского правил вывода типа

Дисклеймер: Возможно моё предположение, что приведённый пример имеет отношение к разрешению имён, ошибочное

Есть такой код: https://godbolt.org/z/bEEjP3x16

#include <functional>

int foo() { return 0; };

using Fn = decltype(foo);

template <typename T>
concept Function = std::is_function_v<T>;

template <typename T>
class TValue {};

template <Function F>
class TValue<F*> {
public:
    F* data;
    constexpr operator F* () const { return data; }
};

// ---------------------------------------
#define MYTEST

#ifdef MYTEST
    template <Function F>
    ::std::function(TValue<F*>) -> ::std::function<F>;
#else
    namespace std {
        template <Function F>
        function(TValue<F*>) -> function<F>;
    }
#endif // MYTEST
// ---------------------------------------

int main() {
    TValue<Fn*> v{&foo};

    std::function f = std::function(v);
}

GCC его замечательно его компилирует. А вот Clang и MSVC выдают ошибки компиляции. (Причём в справке MS указано, что ошибка C2643 является устаревшей https://learn.microsoft.com/en-us/cpp/error-messages/compiler-errors-2/compiler-errors-c2600-through-c2699?view=msvc-170 )

Если скрыть определение MYTEST

//#define MYTEST

и компиляция пойдёт по ветке

namespace std {
    template <Function F>
    function(TValue<F*>) -> function<F>;
}

то все 3 компилятора завершают работу без ошибки.

Вот, собственно, и вопрос. Кто прав? Или это вообще не связано с правилами разрешения имён и причина в чём-то другом?


Ответы (1 шт):

Автор решения: sibedir

Поведение программы на C++ не определено, если она объявляет руководство по выводам для любого шаблона класса стандартной библиотеки.

https://eel.is/c++draft/namespace.std#4.4

Тот случай, когда поведение реально неопределённое. Для std (см. ссылку в вопросе) GCC зачем-то скомпилировал, а для моего собственного namespace https://godbolt.org/z/4n51h4rhK сказал, что так делать нельзя. Лол. Тем не менее это ответ на мой вопрос:

Правы все. Это UB

Спасибо @user7860670

→ Ссылка