将C ++模板参数限制为子类

时间:2010-07-04 15:41:12

标签: c++ templates

如何强制模板参数T成为特定类Baseclass的子类? 像这样:

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

}

7 个答案:

答案 0 :(得分:72)

使用符合C ++ 11的编译器,您可以执行以下操作:

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...
        ...
   }
}

我在CYGWIN环境中使用gcc 4.8.1编译器对此进行了测试 - 所以它也应该在* nix环境中工作。

答案 1 :(得分:44)

在这种情况下,你可以这样做:

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

}

如果T不是Baseclass的子类(或T Baseclass),则不会编译。

答案 2 :(得分:42)

要在运行时执行较少无用的代码,您可以查看: http://www.stroustrup.com/bs_faq2.html#constraints 它提供了一些有效执行编译时测试的类,并产生更好的错误消息。

特别是:

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>();
}

答案 3 :(得分:9)

您不需要概念,但可以使用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
}

请注意,只有在满足条件时才会实例化该函数,但如果不满足条件,则不会提供合理的错误。

答案 4 :(得分:4)

您可以使用Boost Concept CheckBOOST_CONCEPT_REQUIRES

#include <boost/concept_check.hpp>
#include <boost/concept/requires.hpp>

template <class T>
BOOST_CONCEPT_REQUIRES(
    ((boost::Convertible<T, BaseClass>)),
(void)) function()
{
    //...
}

答案 5 :(得分:1)

从C ++ 11开始,您不需要Boost或static_assert。 C ++ 11引入了is_base_ofenable_if。 C ++ 14引入了便利类型enable_if_t,但是如果您对C ++ 11感到困惑,则可以简单地使用enable_if::type来代替。

替代1

David Rodríguez的解决方案可以重写如下:

#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
}

替代2

自C ++ 17起,我们有了is_base_of_v。该解决方案可以进一步重写为:

#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
}

替代3

您也可以只限制整个模板。您可以使用此方法定义整个类。请注意,enable_if_t的第二个参数是如何删除的(先前已设置为void)。它的默认值实际上是void,但这并不重要,因为我们没有使用它。

#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
}

从模板参数的documentation中,我们看到typename = enable_if_t...是一个具有空名称的模板参数。我们只是使用它来确保类型定义存在。特别是,如果enable_if_t不是Base的基数,则不会定义T

上面的技术在enable_if中作为示例给出。

答案 6 :(得分:0)

通过调用模板中存在于基类中的函数。

如果尝试使用无法访问此函数的类型实例化模板,则会收到编译时错误。