0

Basically I have 4 classes:

  • OverVoid
  • Meta: that inherits OverVoid
  • Physical: which has nothing to do with the above
  • Move: a templated class

I want move's template to accept objects of only OverVoid type i.e. OverVoid and Meta.

class OverVoid{
public:

    virtual ~OverVoid(){
    };
};

class Meta: public OverVoid{

};

class Physical{
public:
};

template<typename _Ty>
class Move{

};

I want an error to be trown at compile time, I know there is a way with boost but I cannot use Boost (dev issues with my company)

any ideas?

Wissam Y. Khalil
  • 133
  • 1
  • 5
  • 13

3 Answers3

6

The simplest thing is just a static_assert:

template<typename _Ty>
class Move {
    static_assert(std::is_base_of<OverVoid, _Ty>::value, 
                  "_Ty must inherit from OverVoid.");
};

Note that this allows OverVoid to be a private or inaccessible base. If you want to require that it's a public base, you could instead require:

    static_assert(std::is_convertible<_Ty*, OverVoid*>::value, 
                  "_Ty must inherit publicly from OverVoid.");
Barry
  • 286,269
  • 29
  • 621
  • 977
1

You can hide the template definition for classes not of type OverVoid

template<typename _Ty, 
         class = typename std::enable_if<std::is_base_of<OverVoid, _Ty>::value>::type>
class Move{

};

You then get an error when attempting to compile a class of non-OverVoid type.

int main() {

  Move<Meta> a;
  Move<OverVoid> b;
  Move<Physical> c;
  // your code goes here
  return 0;
}

Error:

prog.cpp: In function 'int main()':
prog.cpp:29:15: error: no type named 'type' in 'struct std::enable_if<false,    void>'
Move<Physical> c;
lcs
  • 4,227
  • 17
  • 36
1

Use std::enable_if:

template <typename T>
struct is_overvoid_or_meta
{
     static const bool value = false;
};

template <> struct is_overvoid_or_meta<OverVoid>
{
     static const bool value = true;
};

template <> struct is_overvoid_or_meta<Meta>
{
     static const bool value = true;
};

//Add specialization for all valid types - this allows you to more precisely tell, what types can be used as a template argument for Move

And then:

template<typename _Ty>
class Move
{
     typedef std::enable_if<is_overvoid_or_meta<_Ty>::value, _Ty>::type Type;
};

You will get compile-time error for every type, that is not OverVoid or Meta (or, more general, for every T, for which is_overvoid_or_meta<T>::value is false - if you will add more of them in the future, you may want to chnge is_overvoid_or_meta to more general, like is_acceptable_by_move or something):

int main()
{
    Move<OverVoid> m1;
    Move<Meta> m2;
    Move<int> m3;
    return 0;
}

Output:

error: no type named 'type' in 'struct std::enable_if'

typedef typename std::enable_if::value, _Ty>::type Type;

Live sample.

This is very nice solution, because it cannot be tricked - additional template parameter for Move can always be specified manually (unless OverVoid and Meta are not exposed to client).

Mateusz Grzejek
  • 11,698
  • 3
  • 32
  • 49