You have violated one definition rule (ODR). So what exactly is happening? There is no specialization in main.cpp for special::call<string> . Therefore, the compiler generates an instance of the template in this translation unit (TU), which outputs "not so special". In special.cpp there is a complete specialization, declared and defined, so the compiler puts this definition in another translation unit. Thus, you have two different definitions of the same function in two different translation units, which is a violation of ODR, which means that this behavior is undefined.
In theory, the result can be anything. Compiler error, crash, quiet online pizza order, whatever. Even other behavior in debugging and release compiles.
In practice, I assume the following: when linking a debug assembly, Linker sees the same symbol defined twice in two TUs, which is allowed only for templates and built-in functions. Due to ODR, he can assume that both definitions are equivalent and choose one from special.cpp , so you get the behavior you expect by coincidence.
During release build, the compiler builds a special::call<string> during compilation of main.cpp , so you get the only behavior observed in this TU: "not so important."
So how can you fix this?
To have only one definition for this specialization, you must define it in one TU, just as you do, but you must declare that there is a full specialization in any other TU, which means that the specialization exists in the special.h header:
// in special.h template<> void special::call(const std::string&);
Or, as seen more often, define it in the header, so it appears in every TU. Since fully specialized function templates are normal functions, you need to define it in a line:
// in special.h template<> inline void special::call(const std::string&) { puts("very special"); }
Arne mertz
source share