Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ class template specialization, without having to reimplement everything

I have a templatized class like so :

template<typename T>
class A
{
    protected:
    std::vector<T> myVector;

    public:
    /*
    constructors + a bunch of member functions here
    */
}

I would like to add just ONE member function that would work only for 1 given type of T. Is it possible to do that at all without having to specialize the class and reimplement all the other already existing methods?

Thanks

like image 802
bob kaggle Avatar asked Aug 25 '14 12:08

bob kaggle


2 Answers

The simplest and cleanest solution is to use a static_assert() in the body of a method, rejecting other types than the selected one (in the below example only integers are accepted):

#include <type_traits>  
#include <vector>

template <typename T>
class A
{
public:
    void onlyForInts(T t)
    {
        static_assert(std::is_same<T, int>::value, "Works only with ints!");
    }

protected:
    std::vector<T> myVector;
};

int main()
{
    A<int> i;
    i.onlyForInts(1); // works !

    A<float> f;
    //f.onlyForInts(3.14f); // does not compile !
}

OK CASE DEMO NOK CASE DEMO

This utilizes the fact that a compiler instantiates a member function of a class template only when one is actually used (not when the class template is instantiated itself). And with the above solution, when a compiler tries to do so, it fails due to the execution of a static_assert.

C++ Standard Reference:

§ 14.7.1 Implicit instantiation [temp.inst]

  1. Unless a function template specialization has been explicitly instantiated or explicitly specialized, the function template specialization is implicitly instantiated when the specialization is referenced in a context that requires a function definition to exist. Unless a call is to a function template explicit specialization or to a member function of an explicitly specialized class template, a default argument for a function template or a member function of a class template is implicitly instantiated when the function is called in a context that requires the value of the default argument.

  2. [ Example:

    template<class T> struct Z {
      void f();
      void g();
    };
    
    void h() {
      Z<int> a;     // instantiation of class Z<int> required
      Z<char>* p;   // instantiation of class Z<char> not required
      Z<double>* q; // instantiation of class Z<double> not required
      a.f();        // instantiation of Z<int>::f() required
      p->g();       // instantiation of class Z<char> required, and
                    // instantiation of Z<char>::g() required
    }
    

    Nothing in this example requires class Z<double>, Z<int>::g(), or Z<char>::f() to be implicitly instantiated. — end example ]

like image 182
Piotr Skotnicki Avatar answered Nov 16 '22 02:11

Piotr Skotnicki


Yes, it's possible in C++03 with CRTP (Curiously recurring template pattern):

#include <numeric>
#include <vector>

template<typename Derived, typename T>
struct Base
{
};

template<typename Derived>
struct Base<Derived, int>
{
    int Sum() const
    {
        return std::accumulate(static_cast<Derived const*>(this)->myVector.begin(), static_cast<Derived const*>(this)->myVector.end(), int());
    }
};

template<typename T>
class A : public Base<A<T>, T>
{
    friend class Base<A<T>, T>;

protected:
    std::vector<T> myVector;

public:
    /*
    constructors + a bunch of member functions here
    */
};

int main()
{
    A<int> Foo;
    Foo.Sum();
}
like image 13
Fytch Avatar answered Nov 16 '22 00:11

Fytch