tag:blogger.com,1999:blog-13960885.post2562098398259430233..comments2024-03-26T02:03:01.072-07:00Comments on C++ Truths: Function Template Overload Resolution and Specialization AnomalySumanthttp://www.blogger.com/profile/11957855386259543653noreply@blogger.comBlogger4125tag:blogger.com,1999:blog-13960885.post-37445206132883756562008-05-06T02:34:00.000-07:002008-05-06T02:34:00.000-07:00A quote from the blessed standard §3.2 One definit...A quote from the blessed standard §3.2 One definition rule, clause 5:<BR/><BR/>There can be more than one definition of a class type (clause 9), enumeration type (7.2), <B>inline function with external linkage (7.1.2),</B> class template (clause 14), <B>non-static function template (14.5.5),</B> static data member of a class template (14.5.1.3), member function of a class template (14.5.1.1), <B>or template specialization for which some template parameters are not specified (14.7, 14.5.4)</B> in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements...<BR/><BR/>The implication of this clause is that full function specialisations obey the same rules as regular (non-template) functions, not function templates.<BR/><BR/>Here is an example:<BR/><BR/>// foo.h<BR/>template<class T> void foo(T) {}<BR/>template<> void foo(int) {}<BR/><BR/>If this header is included in more than one translation unit (.cc/.cpp), the linker complains about foo(int) being defined in several translation units, even if that specialisation is never used (called, or the address is taken).<BR/><BR/>To fix this, foo(int) specialisation needs to be declared inline, or static, or its definition must be removed from the header. On the other hand, function template need not be inline, as the standard provides relaxed one definition rules for templates.<BR/><BR/>The latter is often exploited to put static members in the headers. Exampe:<BR/><BR/>// some.h<BR/>struct some<BR/>{<BR/> static int member;<BR/>};<BR/>int some::member = 0;<BR/><BR/>This header is going to cause multiple some::member definition linker error when included in more than one translation unit. A workaround:<BR/><BR/>template<class T><BR/>struct static_member<BR/>{<BR/> static T member;<BR/>};<BR/><BR/>// static data member of a class template (14.5.1.3),<BR/>// can be defined in many translation units.<BR/>template<class T><BR/>T static_member<T>::member = T();<BR/><BR/>struct some : static_member<int><BR/>{<BR/> // not a template, but still has its static member declared in the header.<BR/>};<BR/><BR/>Returning back to function templates, function overloading is often easier to deal with and can be used to simulate (non-existent) partial function specialisation:<BR/><BR/>template<class T> struct type {}; // boost::type<><BR/>// generic implementation<BR/>template<class T, class U> void foo_impl(type<T>, type<U>);<BR/>// "partial" overload for second argument int<BR/>template<class T> void foo_impl(type<T>, type<int>); <BR/><BR/>template<class T, class U><BR/>void foo() // interface for foo_impl<BR/>{<BR/> // convert template arguments to typed values,<BR/> // so that regular function overloading can be used.<BR/> foo_impl(type<T>(), type<U>());<BR/>}<BR/><BR/>int main()<BR/>{<BR/> foo<void, void>();<BR/> foo<void, int>();<BR/>}Maxim Yegorushkinhttps://www.blogger.com/profile/13335665761944189051noreply@blogger.comtag:blogger.com,1999:blog-13960885.post-31147326940810938832008-05-05T21:01:00.000-07:002008-05-05T21:01:00.000-07:00Good point! Using good old function overloading ma...Good point! Using good old function overloading makes perfect sense and solves the problem of reordering. But after all the fun is in the least explored corners of C++. I added a para in the original post describing the better alternative of overloading. Having said that, is it a violation of Onde Definition Rule (ODR) to allow two identical full explicit function template specializations (f<>(int *))?Sumanthttps://www.blogger.com/profile/11957855386259543653noreply@blogger.comtag:blogger.com,1999:blog-13960885.post-81775125478520480502008-05-05T01:35:00.000-07:002008-05-05T01:35:00.000-07:00Not sure, though, if you quoted the right excerpt....Not sure, though, if you quoted the right excerpt. There is no partial specialisation for functions in the current standard. That excerpt applies to class templates only.<BR/><BR/>There is no reason for void f<>(int*) to be a full function template specialisation. If you make it just a function overload, as girman suggested, reordering the declarations will not produce surprising results.Maxim Yegorushkinhttps://www.blogger.com/profile/13335665761944189051noreply@blogger.comtag:blogger.com,1999:blog-13960885.post-89504962565808404792008-04-03T03:28:00.000-07:002008-04-03T03:28:00.000-07:00Yes. It's interesting behavior. As for me, I prefe...Yes. It's interesting behavior. <BR/>As for me, I prefer to use not explicit specializations, but pure overloaded functions instead.<BR/><BR/>If you'll replace<BR/><BR/>template<><BR/>void f<>(int*) { /*bla-bla-bla*/ }<BR/><BR/>with<BR/><BR/>void f(int*) { /*bla-bla-bla*/ }<BR/><BR/>problem will gone.<BR/><BR/>Not-template functions have always better match for compiler.<BR/><BR/>But.... I don't know... May be there are some situations, when we'll have to use only template specializations, and pure functions overloads wouldn't work?Anonymousnoreply@blogger.com