0

I'm trying to write a template function, but I have trouble specializing it for vector<> and another class at the same time. Here is the code I'm using :

// template definition
template< class T >
void f( const T& value) 
{
    cout << "DEFAULT" << endl;
}

// specialization for MyClass
template< class T >
void f<>  ( const MyClass & value )
{
    cout << "MyClass" << endl;
}

// specialization for vector
template< class T >
void f<>( const std::vector<T> & v )
{
    cout << "vector" << endl;
}

MyClass and MyClass2 are defined as:

class MyClass{
virtual void a() = 0;
};

class MyClass2 : public MyClass{
    void a(){}
};

Finally, the main function:

int main(int nArgs, char *vArgs[]){

    MyClass2 e;
    f<MyClass>(e);

}

Here is the error I get when I try compiling it using Visual Studio 2010:

c:\program files (x86)\microsoft visual studio 10.0\vc\include\vector(869): error C2259: 'MyClass' : cannot instantiate abstract class

This seems to be very specific to this particular situation: As soon as I remove the const modifiers, I change the vector into a list or I make MyClass concrete, everything works. But for my problem I need for this particular situation to work.

Is anybody having the same error as me, and more importantly does anybody know a fix/workaround for this?

Zong
  • 6,160
  • 5
  • 32
  • 46

3 Answers3

0

You have mistakes in specialization syntax.

Probably, it should look like this:

// MyClass
class MyClass{
virtual void a() = 0;
};

class MyClass2 : public MyClass{
    void a(){}
};

// template definition
template< class T >
void f(const T& value)
{
    cout << "DEFAULT" << endl;
};

// specialization for MyClass
template<>
void f(const MyClass & value)
{
    cout << "MyClass" << endl;
};

// specialization for vector of MyClass
template<>
void f(const std::vector<MyClass> & v)
{
    cout << "vector" << endl;
}

int main()
{
    // Using template for any type
    f(2);

    // Using specialization for MyClass
    MyClass2 e;
    f<MyClass>(e);

    // Using specialization for vector<MyClass>
    vector<MyClass> vM;
    f(vM);
}
Anton K
  • 4,658
  • 2
  • 47
  • 60
  • I can't compile your code, MyClass is abstract and I can't instantiate it in a vector. – Arthur Ball May 13 '14 at 17:58
  • I added MyClass to the sample. Now it should be compiled. You don't need to instantiate it in the vector – Anton K May 13 '14 at 18:03
  • Although this code works fine for me under GCC 4.7.2 and VS 2013, it will not build under VS 2010, and so has the same issues the OP reported originally. – Rook May 13 '14 at 18:05
  • `std::vector` with elements which type is an abstract class? Looks like incorrect code... – Constructor May 13 '14 at 18:10
0

I believe this:

// specialization for vector
template< class T >
void f<>( const std::vector<T> & v )
{
    cout << "vector" << endl;
}

is not possible (even if your syntax were corrected, as Anton did in his answer), because it is not a full specialization of f (there are unbound type parameters). Partial function specialization is not allowed under the C++ standard.

There are a few other questions on Stack Overflow involving similar code with similar issues. This one (and the winning answer) seems to be quite relevant: Why function template cannot be partially specialized?

You can peruse the C++ standards for yourself, if you were feeling particularly masochistic. You might start from section 14.7.3 ("Explicit specialization") at page 368 of this document: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf (which is a semi-recent draft, but not the most up to date. It is free, however.)

Community
  • 1
  • 1
Rook
  • 5,734
  • 3
  • 34
  • 43
  • I think you find the root cause : "Partial function specialization is not allowed under the C++ standard". Still I'm wondering why when I change the vector into a list in the specialized function parameter, my code compiles fine, and I'm able to call `f(e)`. I suppose you would say that it's "by chance"? – Arthur Ball May 13 '14 at 18:14
  • @ArthurBall I'm really not at all sure why the `list` specialisation works, and the `vector` one doesn't. I'd be tempted to chalk it up to some particular quirk of VS 2010; it has an awful lot of those (the code is describing nonstandard behaviour, after all). I'm not able to acutally instantiate a `list` under VS 2010, however... that does seem like a specific compiler or library issue as other compilers manage that bit okay. – Rook May 13 '14 at 18:19
0

As other answers have indicated:

  • your syntax for specialization is wrong
  • you cannot partially specialize a template function

...does anybody know a fix/workaround for this?

Since you are using the template argument in the argument list, you can use overloaded functions.

template <class T>
void f(const T& value)
{
    std::cout << "DEFAULT" << std::endl;
}

void f(const MyClass& value)
{
    std::cout << "MyClass" << std::endl;
}

template <class T>
void f(const std::vector<T>& v) // this is an overload, not a specialization
{
    std::cout << "vector" << std::endl;
}

int main()
{
    f(1);
    MyClass2 e;
    f(e);
    f(std::vector<int>());
}
D Drmmr
  • 1,223
  • 8
  • 15
  • You're right, the `vector` version of my function is not a specialization, it is an overload. Though, I find it weird that partial specialization works fine for classes and not for functions. – Arthur Ball May 14 '14 at 08:38
  • @ArthurBall I don't think it would play well with overload resolution. Besides, functions and classes are different things, so template functions and template classes are too. It's also not possible to deduce the template argumemnts of a class, e.g. when calling a constructor. I miss that more than partial specialization of template functions. – D Drmmr May 14 '14 at 17:59