将 C++ 模板参数限制为子类
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3175219/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Restrict C++ Template Parameter to Subclass
提问by phant0m
How can I force a template parameter T
to be a subclass of a specific class Baseclass
?
Something like this:
如何强制模板参数T
成为特定类的子类Baseclass
?像这样的东西:
template <class T : Baseclass> void function(){
T *object = new T();
}
采纳答案by sepp2k
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 isBaseclass).
如果 T 不是 Baseclass 的子类(或 T是Baseclass),这将不会编译。
回答by Vish Desai
With a C++11 compliant compiler, you can do something like this:
使用符合 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...
...
}
}
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.
我已经在 CYGWIN 环境中使用 gcc 4.8.1 编译器对此进行了测试 - 所以它也应该在 *nix 环境中工作。
回答by Douglas Leeder
To execute less useless code at runtime you can look at: http://www.stroustrup.com/bs_faq2.html#constraintswhich provides some classes that perform the compile time test efficiently, and produce nicer error messages.
要在运行时执行较少无用的代码,您可以查看:http: //www.stroustrup.com/bs_faq2.html#constraints,它提供了一些可以有效执行编译时测试并产生更好的错误消息的类。
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>();
}
回答by David Rodríguez - dribeas
You don't need concepts, but you can use SFINAE:
你不需要概念,但你可以使用 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.
请注意,这只会在满足条件时实例化函数,但如果不满足条件,它将不会提供合理的错误。
回答by justinpc
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.
从 C++11 开始,您不需要 Boost 或static_assert
. C++11 引入了is_base_of
和enable_if
. C++14 引入了便利类型enable_if_t
,但如果你被 C++11 卡住了,你可以简单地enable_if::type
改用。
Alternative 1
备选方案 1
David Rodríguez's solution may be rewritten as follows:
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
}
Alternative 2
备选方案 2
Since C++17, we have is_base_of_v
. The solution can be further rewritten to:
从 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
}
Alternative 3
备选方案 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.
您也可以只限制整个模板。您可以使用此方法来定义整个类。注意第二个参数是如何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
}
From the documentationof 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
.
从模板参数的文档中,我们看到这typename = enable_if_t...
是一个名称为空的模板参数。我们只是使用它来确保类型的定义存在。特别是,enable_if_t
如果Base
不是 的基础,则不会被定义T
。
The technique above is given as an example in enable_if
.
上述技术在 中作为示例给出enable_if
。
回答by Daniel Trebbien
You could use Boost Concept Check's BOOST_CONCEPT_REQUIRES
:
您可以使用Boost Concept Check的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()
{
//...
}
回答by DanDan
By calling functions inside your template that exist in the base class.
通过调用基类中存在的模板内的函数。
If you try and instantiate your template with a type that does not have access to this function, you will receive a compile-time error.
如果您尝试使用无权访问此函数的类型实例化模板,您将收到编译时错误。