Explicit template instantiation with member template function

11,007

I'm confused by this:

I don't want to use a catch-all:

template class Test<int, double>

because the overload get(const int&) will not be defined for all possible explicit instantiations and hence the compiler will throw a fit for types which dont support it.

Explicitness of one specialization does not affect the semantics of other specializations.

The overload get(const int&) is simply a member function, and it will be instantiated for explicit and implicit specializations like any other.

Explicit instantiation can only slow down the compiler. It only processes each instantiation at most once. Unused parts of an implicit instantiation may be ignored, but by explicitly instantiating, you are forcing it to handle the whole thing. Not that a single instantiation is likely to take a measurable amount of time, anyway.

To run through errors in the code:

template <class T, class S > // arguments unused
class Test
{
public:
 template< typename T1 > 
 void* get( const T1& );
 void* get(const int& ); // overload of the above
};

typedef Test<int, double> foo;

// illegal to instantiate a template before its members are defined

inline template class Test<int, double>; // "inline template" is meaningless
template void* foo::get(int const&); // typedef name "foo" cannot be used here
/* ^ illegal to explicitly instantiate a member of an already explicitly 
   instantiated template */

Update:

The error results from the non-template overload not having priority over the member template.

Unfortunately, you cannot explicitly specialize a member template of a template parent. The workaround at that question is to partially specialize, but that won't work because you have a function template.

Workaround #2 is SFINAE.

 #include <boost/enable_if.hpp>
 #include <boost/type_traits.hpp>

 template< typename T1 > 
 boost::disable_if< boost::is_same<T1,int>, void* >::type
     get( const T1& ); // "turn off" declaration if in conflict

 void* get(const int& ); // unambiguous overload of the above

If you can't use Boost,

 template< class T >
 struct disable_if_int { typedef void *type; };

 template<>
 struct disable_if_int<int> {};

...

 template< typename T1 > 
 disable_if_int< T1 >::type get( const T1& );

 void* get(const int& ); // unambiguous overload of the above
Share:
11,007
Vagabond
Author by

Vagabond

Updated on July 14, 2022

Comments

  • Vagabond
    Vagabond almost 2 years

    I have a template class with a template member function. I want to explicitly instantiate the class to avoid a drastic compilation slowdown. I am using g++ 4.1.2. I get ambiguous template specialization errors from the compiler. This the shortest code which will reproduce the problem:

    template <class T, class S >
    class Test
    {
    public:
     template< typename T1 > 
     void* get( const T1& );
     void* get(const int& ); //Specialization of the above
    };
    
    typedef Test<int, double> foo;
    
    //instantiate
    inline template class Test<int, double>;
    template void* foo::get(int const&);
    

    I don't want to use a catch-all:

    template class Test<int, double>
    

    because the overload get(const int&) will not be defined for all possible explicit instantiations and hence the compiler will throw a fit for types which dont support it.

    This code compiles in visual studio (without the inline preceeding template, which is a gcc specific extenstion). Can somebody please throw some light into how I get this code fragment to compile?

    UPDATE: This is the error I get:

    g++    -c -o template.o template.cpp
    template.cpp:14: error: ambiguous template specialization ‘get<>’ for ‘void* Test<int, double>::get(const int&)’
    template.cpp:7: error: candidates are: void* Test<T, S>::get(const int&) [with T = int, S = double]
    template.cpp:6: error:                 template<class T1> void* Test::get(const T1&) [with T1 = T1, T = int, S = double]
    

    UPDATE2: Thanks for the solution, it does not compile though. Specializations are not allowed inside a class. The error is:

    g++    -c -o template.o template.cpp
    template.cpp:7: error: explicit specialization in non-namespace scope ‘class Test<T, S>’
    template.cpp:7: error: enclosing class templates are not explicitly specialized
    template.cpp:8: error: ‘get’ is not a template function
    template.cpp: In instantiation of ‘void* Test<T, S>::get(const T1&) [with T1 = int, T = int, S = double]’:
    template.cpp:15:   instantiated from here
    template.cpp:15: error: explicit instantiation of ‘void* Test<T, S>::get(const T1&) [with T1 = int, T = int, S = double]’ but no definition available
    make: *** [template.o] Error 1