How to enforce template parameter class to derive from super with an anonymous template parameter

前端 未结 2 541
离开以前
离开以前 2021-01-27 06:27

I have a couple of template classes

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

template < class Transition         


        
相关标签:
2条回答
  • 2021-01-27 07:12

    From what I understood from your question, here is a quick solution that I have:

    template < class Cost >
    class Transition {
      public:
        virtual Cost getCost() = 0;
    };
    
    template <typename T>
    class Der : public Transition<T>
    {
    public:
      T getCost() override {
      }
    };
    
    template < class Transition >
    class State;
    
    template <template <typename> class TransitionCl, typename Cost>
    class State <TransitionCl<Cost>> {
    public:
            State(){
                static_assert(
                    std::is_base_of< Transition< Cost >, TransitionCl<Cost> >::value,
                    "TransitionCl class in State must be derived from Transition< Cost >"
                );
            }
    };
    
    int main()
    {
      Der<int> d;
      State<decltype(d)> s;
    
      return 0;
    }
    

    In the above example, you dont have to pass the 'Cost' type while creating State object.

    ===== UPDATE ======

    template <typename Cost>
    class Transition
    {
    public:
        virtual Cost getCost() = 0;
        virtual ~Transition() {}
    };
    
    class TD: public Transition<int>
    {
    public:
        int getCost() override {
            std::cout << "getCost override" << std::endl;
            return 42;
        }
    };
    
    namespace detail {
        template <typename T>
        struct is_base_of_cust {
            // This is a bit hacky as it is based upon the internal functions
            // (though public) of the Transition class.
            using CostType = decltype(std::declval<T>().getCost());
            static const bool value = std::is_base_of<Transition<CostType>, T>::value;
        };
    };
    
    template <class TransitionCl>
    class State
    {
    protected:
        State() {
            static_assert(
                detail::is_base_of_cust<TransitionCl>::value,
                "TransitionCl class in State must be derived from Transition<Cost>"
            );
        }
    public:
        virtual void apply(const TransitionCl&) = 0;
        virtual ~State() {}
    };
    
    
    class StateImpl: public State<TD>
    {
    public:
        void apply(const TD&) override {
            std::cout << "StateImpl::apply" << std::endl;
        }
    };
    
    
    int main() {
        StateImpl impl;
        return 0;
    }
    
    0 讨论(0)
  • 2021-01-27 07:16

    One way is to use the return type of getCost() (but it may give you an uglier error messgae if TransactionCl() doesn't have such a public member function).

    std::is_base_of< Transition< decltype(TransitionCl().getCost()) >, TransitionCl >::value,
    

    Another option is adding a typedef to the base class:

    template < class Cost >
    class Transition {
      public:
        typedef Cost Cost_Type;    // <-------
        virtual Cost getCost() = 0;
    };
    

    Then you can remove State's typename Cost parameter and use the typedef instead in your static assert...

    std::is_base_of< Transition< typename TransitionCl::Cost_Type >, TransitionCl >::value,
    
    0 讨论(0)
提交回复
热议问题