Примечание к C ++ 17, 17.5.7.2 гласит, что
Когда идентификатор шаблона относится к специализации шаблона псевдонима, он эквивалентен связанному типу, полученному путем подстановкиего аргументы шаблона для параметров шаблона в идентификаторе типа шаблона псевдонима.[Примечание: имя шаблона псевдонима никогда не выводится.- примечание конца]
Это одностадийный процесс, и последующая замена аргументов шаблона здесь не применяется.
Давайте поиграем с вашим первым примером:
template <template <typename> class Trait, typename Ret, typename T>
struct is_detected {};
struct A {
static int Get() {
return 0;
}
};
template <typename T>
using Get_t = decltype(T::Get());
template <typename T>
struct Get_t2 {
using Type = decltype(T::Get());
};
template <template <typename> class Trait, typename T>
struct is_detected<Trait, typename Trait<T>::Type, T> : std::true_type {};
template <template <typename> class Trait, typename T>
struct is_detected<Trait, Trait<T>, T> : std::true_type {};
СейчасВы можете видеть, что:
is_detected<Get_t2, int, A>::value // works, because it is normal type
is_detected<Get_t, int, A>::value // not, because it is alias
Интересно, что ваша идея с void_t
работает из-за C ++ 17, 17.5.7.3
Однако, если идентификатор шаблона равензависимая, последующая замена аргумента шаблона все еще применяется к идентификатору шаблона
Я рекомендую использовать шаблоны на основе структуры, а не на основе псевдонимов, когда это возможно.Иначе заставить его работать будет так же трудно, как разжечь его самосожжение