tags:

views:

550

answers:

2

An explicit instantiation of a static template member function keeps failing to compile with the message error C2785: 'at_Intermediate CUtil::convert_variant(const VARIANT &)' and '<Unknown>' have different return types

When I make a corresponding class with non-static member functions, the compiler likes me.

// utility class - static methods
struct CUtil {
      template< typename at_Intermediate > static at_Intermediate convert_variant( const VARIANT &v ) ;

      template<> static VARIANT convert_variant<VARIANT >( const VARIANT &v ) { return v; } // 
      template<> static double  convert_variant<double  >( const VARIANT &v ) { return v.dblVal; }
      template<> static long    convert_variant<long    >( const VARIANT &v ) { return v.lVal  ; }
      template<> static BSTR    convert_variant<BSTR    >( const VARIANT &v ) { return v.bstrVal; }
};

This is a composed question:

  1. Why does the compiler complain about a function "Unknown" while it's clearly known?

  2. What triggers this message - it disappears when the function is made global or non-static.

EDIT:

after some useful hints from Josh: is it not allowed to explicitly instantiate template functions within the class declaration?

+2  A: 

Try it this way:

struct CUtil {
    template< typename T > 
    static T convert_variant(const VARIANT &);
};

template<> int CUtil::convert_variant<int>(const VARIANT &);
template<> VARIANT CUtil::convert_variant<VARIANT>(const VARIANT &);

You can't explicitly specialize a template inside a class scope. See here.

The wierd issue with VS2008 is that this does work.

struct CUtil {
    template< typename T > 
    static T convert_variant(const VARIANT &);
    template<> 
    static int convert_variant<int>(const VARIANT &);
};

And this:

struct CUtil {
    template< typename T > static void convert_variant(T);
    template<> static void convert_variant<VARIANT >(VARIANT);
};
Eclipse
points in the direction of non-pod template arguments?
xtofl
Although test is a POD type.
Eclipse
... Comeau also reacts to the explicit instantiation whithin the class body... Defining the functions outside yields OK result.
xtofl
at Codepad.org: same result (explicit specialization in non-namespace scope 'struct CUtil')
xtofl
I'm just working with VS2008
Eclipse
your third solution should get rid of the 'static' keyword (you're not declaring there)
xtofl
yeah - I just caught that.
Eclipse
btw - though you didn't get to the answer, I +1'd your post 'cause it really helped me find the issue.
xtofl
+2  A: 

Apparently you may only use explicit template specialization at namespace scope although I can't find this in the standard (but GCC says as much). The following works for me (on GCC):

struct CUtil {
    template< typename at_Intermediate > static at_Intermediate convert_variant( const VARIANT &v ) ;
};

template<> VARIANT CUtil::convert_variant<VARIANT >( const VARIANT &v ) { return v; }
template<> double  CUtil::convert_variant<double  >( const VARIANT &v ) { return v.dblVal; }
template<> long    CUtil::convert_variant<long    >( const VARIANT &v ) { return v.lVal  ; }
template<> BSTR    CUtil::convert_variant<BSTR    >( const VARIANT &v ) { return v.bstrVal; }

EDIT It is in the standard:

14.7.2.5:

An explicit instantiation of a class or function template specialization is placed in the namespace in which the template is defined. An explicit instantiation for a member of a class template is placed in the namespace where the enclosing class is defined. An explicit instantiation for a member template is placed in the namespace where the enclosing class or class template is defined.

(All emphasis added by me.)

Konrad Rudolph
that's an explicit specialization tho, not instantiation. 14.7.3p2: "An explicit specialization shall be declared in the namespace of which the template is a member, or, for member templates, in the namespace of which the enclosing class or enclosing class template is a member." fits in your case :)
Johannes Schaub - litb
ah nvm, i just see it's just what the OP used too, wasn't your fault :) but maybe you can correct him about that?
Johannes Schaub - litb
What's 'the OP'?
xtofl
it's the OriginalPoster, the guy posted the question. i think you know what the diff between the two is, but in case not: an explicit instantiation would instantiate the template for a given type in the current translation unit (so clients can use the template somewhere else without needing...
Johannes Schaub - litb
... the template code. explicit specialization puts a different code for different types. (in your code, the difference is that you return a different member in each specialization).
Johannes Schaub - litb
@litb: In my understanding, an explicit specialization actually also *is* an instantiation. I might be wrong, though. Particularly considering that there is a separate syntax for the instantiation.
Konrad Rudolph
@litb: Please consider http://pastie.org/356862. AFAIK, this shouldn't work if template specialization didn't also instantiate the template.
Konrad Rudolph