C++ class template of specific baseclass

C++GenericsInheritanceTemplates

C++ Problem Overview


Let's say I have the classes:

class Base{};

class A: public Base{
    int i;
};

class B:public Base{
    bool b;
};

And now I want to define a templated class:

template < typename T1, typename T2 >
class BasePair{
    T1 first;
    T2 second;
};

But I want to define it such that only decendants of class Base can be used as templateparameters.

How can I do that?

C++ Solutions


Solution 1 - C++

C++11 introduces <type_traits>

template <typename T1, typename T2>
class BasePair{
static_assert(std::is_base_of<Base, T1>::value, "T1 must derive from Base");
static_assert(std::is_base_of<Base, T2>::value, "T2 must derive from Base");

    T1 first;
    T2 second;
};

Solution 2 - C++

More exactly:

class B {};
class D1 : public B {};
class D2 : public B {};
class U {};

template <class X, class Y> class P {
	X x;
	Y y;
public:
	P()	{
		(void)static_cast<B*>((X*)0);
		(void)static_cast<B*>((Y*)0);
	}
};

int main() {
    P<D1, D2> ok;
	P<U, U> nok; //error
}

Solution 3 - C++

C++ doesn’t yet allow this directly. You can realize it indirectly by using a STATIC_ASSERT and type checking inside the class:

template < typename T1, typename T2 >
class BasePair{
    BOOST_STATIC_ASSERT(boost::is_base_of<Base, T1>);
    BOOST_STATIC_ASSERT(boost::is_base_of<Base, T2>);
    T1 first;
    T2 second;
};

Solution 4 - C++

This was a great question! While researching this via this link, I came up with the following, which admittedly isn't much different than the provided solution there. Learn something everyday...check!

#include <iostream>
#include <string>
#include <boost/static_assert.hpp>

using namespace std;

template<typename D, typename B>
class IsDerivedFrom
{
  class No { };
  class Yes { No no[3]; };

  static Yes Test(B*); // declared, but not defined
  static No Test(...); // declared, but not defined

public:
  enum { IsDerived = sizeof(Test(static_cast<D*>(0))) == sizeof(Yes) };
};


class Base
{
public:
    virtual ~Base() {};
};

class A : public Base
{
    int i;
};

class B : public Base
{
    bool b;
};

class C
{
    string z;
};


template <class T1, class T2>
class BasePair
{
public:
    BasePair(T1 first, T2 second)
        :m_first(first),
         m_second(second)
    {
        typedef IsDerivedFrom<T1, Base> testFirst;
        typedef IsDerivedFrom<T2, Base> testSecond;

        // Compile time check do...
        BOOST_STATIC_ASSERT(testFirst::IsDerived == true);
        BOOST_STATIC_ASSERT(testSecond::IsDerived == true);

        // For runtime check do..
        if (!testFirst::IsDerived)
            cout << "\tFirst is NOT Derived!\n";
        if (!testSecond::IsDerived)
            cout << "\tSecond is NOT derived!\n";

    }

private:
    T1 m_first;
    T2 m_second;
};


int main(int argc, char *argv[])
{
    A a;
    B b;
    C c;

    cout << "Creating GOOD pair\n";
    BasePair<A, B> good(a, b);

    cout << "Creating BAD pair\n";
    BasePair<C, B> bad(c, b);
    return 1;
}

Solution 5 - C++

First, fix the declaration

template < class T1, class T2 >
class BasePair{
    T1 first;
    T2 second;
};

Then, you can declare in a base class some private function Foo(); and tell Base class to have BasePair as friend; then in friend constructor you just have to call this function. This way you will get compile-time error when someone tries to use other classes as template parameters.

Solution 6 - C++

class B
{
};
class D : public B
{
};
class U
{
};

template <class X, class Y> class P
{
	X x;
	Y y;
public:
	P()
	{
		(void)static_cast<X*>((Y*)0);
	}
};

Solution 7 - C++

In the answer suggested by unknown(yahoo), it is not required to actually have the variables of type X and Y as members. These lines are sufficient in the constructor:

static_cast<B*>((X*)0);
static_cast<B*>((Y*)0);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMatView Question on Stackoverflow
Solution 1 - C++HashbrownView Answer on Stackoverflow
Solution 2 - C++user213546View Answer on Stackoverflow
Solution 3 - C++Konrad RudolphView Answer on Stackoverflow
Solution 4 - C++RC.View Answer on Stackoverflow
Solution 5 - C++alemjerusView Answer on Stackoverflow
Solution 6 - C++user213546View Answer on Stackoverflow
Solution 7 - C++mukeshkumarView Answer on Stackoverflow