1

So I have the following two classes:

template < class Cost >
class Transformation {
  public:
    virtual Cost getCost() = 0;
};

template < class TransfCl, class Cost >
class State {
    protected:
        State(){
            static_assert(
                std::is_base_of< Transformation< Cost >, TransfCl >::value,
                "TransfCl class in State must be derived from Transformation< Cost >"
            );
        }
    public:
        virtual void apply( const TransfCl& ) = 0;
};

But would like to, instead, be able to drop the Cost template parameter to State, because State's functionality is completely independent of Cost. This way, I could create non-abstract classes using a syntax similar to this:

class TransfImpl : public Transformation< int >{
    public: int getCost(){ return 0; }
};

class StateImpl : public State< TransfImpl >{
    public:
        StateImpl(){
            static_assert(
                std::is_base_of< Transformation, TransfImpl  >::value,
                "TransfImpl must inherit from Transformation< Cost >"
            );
        }
        void apply( const TransfImpl & ){}
};

I also wanted to eventually chain this to a third class, which would use the State-derived class as its template parameter, but wouldn't need to also have the Transformation-derived and Cost-derived classes in its template parameters to verify that its State-derived template parameter class is, in fact, derived from State

Danh
  • 5,916
  • 7
  • 30
  • 45
A Frayed Knot
  • 476
  • 5
  • 20
  • Same as http://stackoverflow.com/questions/34670375/how-to-enforce-template-parameter-class-to-derive-from-super-with-an-anonymous-t – Arunmu Jan 14 '16 at 07:10
  • or [std::is_base_of for template classes](http://stackoverflow.com/a/34672753/2684539) – Jarod42 Jan 14 '16 at 09:18

2 Answers2

1

Does this suit your need?

template < class Cost >
class Transformation {
public:
    typedef Cost TransformationCost;
    virtual Cost getCost() = 0;
};

template < class TransfCl, class Cost = typename TransfCl::TransformationCost>
class State {
    static_assert(
                std::is_base_of< Transformation< Cost >, TransfCl >::value,
                "TransfCl class in State must be derived from Transformation< Cost >"
            );
protected:
    State(){}
public:
    virtual void apply( const TransfCl& ) = 0;
};

class TransfImpl : public Transformation< int >{
public:
    int getCost(){ return 0; }
};

class StateImpl : public State< TransfImpl >{
public:
   StateImpl(){}
   void apply( const TransfImpl & ){}
};

ADDED: Live Demo

Danh
  • 5,916
  • 7
  • 30
  • 45
1

With

template <template <typename...> class C, typename...Ts>
std::true_type is_template_base_of_impl(const C<Ts...>*);

template <template <typename...> class C>
std::false_type is_template_base_of_impl(...);

template <template <typename...> class C, typename T>
using is_template_base_of = decltype(is_template_base_of_impl<C>(std::declval<T*>()));

You may do

template <class TransfCl>
class State {
protected:
    static_assert(is_template_base_of<Transformation, TransfCl>::value,
                  "TransfCl class in State must be derived from Transformation<Cost>");

    // previous code ...
};
Jarod42
  • 203,559
  • 14
  • 181
  • 302