Помните, как VC6 сходил с ума на специализациях шаблонов функций с одинаковым типом
template<class T> void fun() {}
int main() { f<int>(); f<char>(); }
потому что компилятор давал им одинаковое манглированное имя? А линкер потом наобум брал любую специализацию и подсовывал во все места, нарушая ODR.
Встречайте:
#include <cstdio>
template< template<class>class F > struct say
{
static void hello() { puts(__FUNCSIG__); }
};
template<class> struct alfa {};
template<class> struct beta {};
template<class> using blue = void;
template<class T> using star = T***;
int main()
{
say<alfa>::hello(); // ?hello@?$say@Ualfa@@@@SAXXZ (public: static void __cdecl say<struct alfa>::hello(void))
say<beta>::hello(); // ?hello@?$say@Ubeta@@@@SAXXZ (public: static void __cdecl say<struct beta>::hello(void))
say<blue>::hello(); // ?hello@?$say@$@@SAXXZ ( ?? ?? ::SAXXZ::say<>::hello)
say<star>::hello(); // ?hello@?$say@$@@SAXXZ ( ?? ?? ::SAXXZ::say<>::hello)
}
На этот раз линкер заругался, что в одной секции кода две точки с одинаковым именем. (Кстати, уже весело, невалидный .obj)
Но если похимичить с несколькими единицами трансляции, то — ТАДАМ!!!
Ну и приятная новость для пользователей MSVC 2015: там этот баг уже исправлен.