Restrict C++ Template Parameter to Subclass

前端 未结 7 1426
醉话见心
醉话见心 2020-11-28 22:04

How can I force a template parameter T to be a subclass of a specific class Baseclass? Something like this:

template 

        
相关标签:
7条回答
  • 2020-11-28 22:28

    You don't need concepts, but you can use SFINAE:

    template <typename T>
    boost::enable_if< boost::is_base_of<Base,T>::value >::type function() {
       // This function will only be considered by the compiler if
       // T actualy derived from Base
    }
    

    Note that this will instantiate the function only when the condition is met, but it will not provide a sensible error if the condition is not met.

    0 讨论(0)
  • 2020-11-28 22:30

    With a C++11 compliant compiler, you can do something like this:

    template<class Derived> class MyClass {
    
        MyClass() {
            // Compile-time sanity check
            static_assert(std::is_base_of<BaseClass, Derived>::value, "Derived not derived from BaseClass");
    
            // Do other construction related stuff...
            ...
       }
    }
    

    I've tested this out using the gcc 4.8.1 compiler inside a CYGWIN environment - so it should work in *nix environments as well.

    0 讨论(0)
  • 2020-11-28 22:31

    You could use Boost Concept Check's BOOST_CONCEPT_REQUIRES:

    #include <boost/concept_check.hpp>
    #include <boost/concept/requires.hpp>
    
    template <class T>
    BOOST_CONCEPT_REQUIRES(
        ((boost::Convertible<T, BaseClass>)),
    (void)) function()
    {
        //...
    }
    
    0 讨论(0)
  • 2020-11-28 22:36

    To execute less useless code at runtime you can look at: http://www.stroustrup.com/bs_faq2.html#constraints which provides some classes that perform the compile time test efficiently, and produce nicer error messages.

    In particular:

    template<class T, class B> struct Derived_from {
            static void constraints(T* p) { B* pb = p; }
            Derived_from() { void(*p)(T*) = constraints; }
    };
    
    template<class T> void function() {
        Derived_from<T,Baseclass>();
    }
    
    0 讨论(0)
  • 2020-11-28 22:44

    Since C++11 you do not need Boost or static_assert. C++11 introduces is_base_of and enable_if. C++14 introduces the convenience type enable_if_t, but if you are stuck with C++11, you can simply use enable_if::type instead.

    Alternative 1

    David Rodríguez's solution may be rewritten as follows:

    #include <type_traits>
    
    using namespace std;
    
    template <typename T>
    enable_if_t<is_base_of<Base, T>::value, void> function() {
       // This function will only be considered by the compiler if
       // T actualy derived from Base
    }
    

    Alternative 2

    Since C++17, we have is_base_of_v. The solution can be further rewritten to:

    #include <type_traits>
    
    using namespace std;
    
    template <typename T>
    enable_if_t<is_base_of_v<Base, T>, void> function() {
       // This function will only be considered by the compiler if
       // T actualy derived from Base
    }
    

    Alternative 3

    You could also just restrict the the whole template. You could use this method for defining whole classes. Note how the second parameter of enable_if_t has been removed (it was previously set to void). Its default value is actually void, but it doesn't matter, as we are not using it.

    #include <type_traits>
    
    using namespace std;
    
    template <typename T,
              typename = enable_if_t<is_base_of_v<Base, T>>>
    void function() {
       // This function will only be considered by the compiler if
       // T actualy derived from Base
    }
    

    From the documentation of template parameters, we see that typename = enable_if_t... is a template parameter with an empty name. We are simply using it to ensure that a type's definition exists. In particular, enable_if_t will not be defined if Base is not a base of T.

    The technique above is given as an example in enable_if.

    0 讨论(0)
  • 2020-11-28 22:46

    In this case you can do:

    template <class T> void function(){
        Baseclass *object = new T();
    
    }
    

    This will not compile if T is not a subclass of Baseclass (or T is Baseclass).

    0 讨论(0)
提交回复
热议问题