3

Suppose I have the following code (C++):

template < class Td, class Ud, class Vd>
class Extractor
{
private: 
  // some code here
public:
  // the class has functions to populate these vectors
  vector<Td* >    list_of_layers;
  vector<Ud* >    list_of_resistors;
  vector<Vd* >    list_of_nodes;
}

I wish to impose the restriction that the classes that are used to replace Td, Ud and Vd while instantiating an object of class Extractor are ALWAYS derived from classes (say) T, U and V, respectively. Is it possible?

Chatter
  • 193
  • 8
  • Are you looking for `std::is_base_of`, by any chance? – Igor Tandetnik Jul 23 '14 at 05:10
  • possible duplicate of [Check if class is derived from a specific class (compile, runtime both answers available)](http://stackoverflow.com/questions/18099241/check-if-class-is-derived-from-a-specific-class-compile-runtime-both-answers-a) – Nikos Athanasiou Jul 23 '14 at 05:34
  • Also related http://stackoverflow.com/a/2631689/2567683 – Nikos Athanasiou Jul 23 '14 at 05:39
  • @IgorTandetnik Yes, I think std::is_base_of is what I was looking for. I was trying to focus on templates in my search for solution instead of looking for means to verify inheritance. Thanks Nikos for the related links, they improved my understanding. :) – Chatter Jul 23 '14 at 06:17

2 Answers2

2

You could use type_traits and in particular enable_if in combination with is_base_of like the example below:

#include <type_traits>

class BaseT {};
class BaseU {};
class BaseV {};

class DerivedT : public BaseT {};
class DerivedU : public BaseU {};
class DerivedV : public BaseV {};

template < class Td, class Ud, class Vd, class Enable = void>
class Extractor {
  static_assert(std::is_base_of<BaseT, Td>::value, "Template argument Td is not derived from BaseT");
  static_assert(std::is_base_of<BaseU, Ud>::value, "Template argument Ud is not derived from BaseU");
  static_assert(std::is_base_of<BaseV, Vd>::value, "Template argument Vd is not derived from BaseV");
};

template <class Td, class Ud, class Vd>
class Extractor<Td, Ud, Vd, 
  typename std::enable_if<std::is_base_of<BaseT, Td>::value &&
                          std::is_base_of<BaseU, Ud>::value &&
                          std::is_base_of<BaseV, Vd>::value>::type> {

};

int main() {
  Extractor<DerivedT, DerivedU, DerivedV> dummy;
  Extractor<int, double, int> dummy2; // will fail to compile!!!
}

LIVE DEMO

101010
  • 41,839
  • 11
  • 94
  • 168
  • Nice but the error message in case of type matching failure is pretty misleading. – SomeWittyUsername Jul 23 '14 at 05:24
  • Thanks for the live demo and feedback on the question! @40two: Since I am new to this, can you please explain the code a little bit, as in how the pieces fit together and why (it seems that) we have two definitions of class Extractor? – Chatter Jul 23 '14 at 06:19
  • @Chatter Actually we don't have two definitions but rather one template definition and one template specialization. When you define an object of type `Extractor` C++ will try to match with the template specialization first. If conditions in `enable_if` are met then "OK Charlie good to go", if the conditions in `enable_if` aren't met (i.e., template arguments aren't derived from specific classes) C++ will try to instantiate an `Extractor` object with provided arguments from `Extractor` definition. However, this will fail due to the `static_assert`s with a specific error message HTH :). – 101010 Jul 23 '14 at 06:40
  • 1
    BTW, `std::enable_if` is useless here, `static_assert` is sufficient. – Jarod42 Jul 23 '14 at 07:18
1

Yes. You can use the std::is_base_of trait for that. Add static assertions to your class, e.g.:

static_assert(std::is_base_of<T, Td>::value, "Td must inherit from T");
SomeWittyUsername
  • 18,025
  • 3
  • 42
  • 85