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...
...
}
}
要在运行时执行更少的无用代码,可以查看:www.example.com,它提供了一些类,可以有效地执行编译时测试,并生成更好的错误消息。http://www.stroustrup.com/bs_faq2.html#constraints which provides some classes that perform the compile time test efficiently, and produce nicer error messages. 特别是:
#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
}
#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
}
#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
}
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
}
template <class T> void function()
requires( std::is_base_of_v<Baseclass,T> )
{
T *object = new T();
}
或者,对于频繁使用的约束,可以使用命名概念,这样语法更简洁(@sklott的功劳):
template <std::derived_from<Baseclass> T> void function()
{
T *object = new T();
}
使用约束比使用static_assert好,因为它们允许您拥有function的多个实现,这些实现具有不同的约束。例如,当T从不同的类派生时,您可以拥有另一个实现。如果需要,您还可以拥有一个根本不指定任何约束的默认实现。当没有一个受约束的实现符合条件时由编译器选择。使用static_assert时,这些都不可能。 PS. requires子句非常适合于特殊约束,而命名概念非常适合于频繁使用的约束(您也可以使用concept关键字创建您自己的命名概念)。您可以阅读更多关于约束和应用它们的替代方法here、关于std::is_base_of_vhere和关于std::derived_fromhere。还请务必阅读有关requires expressions的内容,不要将其与requires子句混淆,即使它们共享相同的requires关键字。
8条答案
按热度按时间gdx19jrr1#
使用兼容C++11的编译器,您可以执行以下操作:
我已经在CYGWIN环境中使用gcc 4.8.1编译器对此进行了测试-所以它在 *nix环境中也应该工作。
3xiyfsfu2#
在这种情况下,您可以执行以下操作:
如果T不是Baseclass的子类(或者T * 是 * Baseclass),则不会编译。
6ljaweal3#
要在运行时执行更少的无用代码,可以查看:www.example.com,它提供了一些类,可以有效地执行编译时测试,并生成更好的错误消息。http://www.stroustrup.com/bs_faq2.html#constraints which provides some classes that perform the compile time test efficiently, and produce nicer error messages.
特别是:
vh0rcniy4#
C11引入了
is_base_of
和enable_if
,C14引入了方便的类型enable_if_t
,但是如果你坚持使用C++11,你可以简单地使用enable_if::type
。备选方案1
David Rodríguez的解决方案可以重写如下:
备选方案2
从C++17开始,我们有
is_base_of_v
,解可以进一步改写为:备选方案3
你也可以只限制整个模板。你可以使用这个方法来定义整个类。注意
enable_if_t
的第二个参数是如何被移除的(它之前被设置为void)。它的默认值实际上是void
,但这并不重要,因为我们没有使用它。从模板参数的documentation中,我们看到
typename = enable_if_t...
是一个空名称的模板参数,我们只是使用它来确保类型的定义存在,特别是,如果Base
不是T
的基,enable_if_t
将不会被定义。上面的技术在
enable_if
中作为示例给出。mm5n2pyu5#
您不需要概念,但可以使用SFINAE:
请注意,这将仅在满足条件时示例化函数,但如果不满足条件,则不会提供明显的错误。
laawzig26#
您可以使用Boost Concept Check的
BOOST_CONCEPT_REQUIRES
:l7wslrjt7#
从C++20开始,你可以约束模板参数。一种方法是
requires
子句。你可以在你的情况下使用它如下(即确保T
是一个特定类Baseclass
的子类):或者,对于频繁使用的约束,可以使用命名概念,这样语法更简洁(@sklott的功劳):
使用约束比使用
static_assert
好,因为它们允许您拥有function
的多个实现,这些实现具有不同的约束。例如,当T
从不同的类派生时,您可以拥有另一个实现。如果需要,您还可以拥有一个根本不指定任何约束的默认实现。当没有一个受约束的实现符合条件时由编译器选择。使用static_assert
时,这些都不可能。PS.
requires
子句非常适合于特殊约束,而命名概念非常适合于频繁使用的约束(您也可以使用concept
关键字创建您自己的命名概念)。您可以阅读更多关于约束和应用它们的替代方法here、关于std::is_base_of_v
here和关于std::derived_from
here。还请务必阅读有关requires expressions的内容,不要将其与requires子句混淆,即使它们共享相同的requires
关键字。vwkv1x7d8#
通过调用存在于基类中的模板内的函数。
如果尝试使用无权访问此函数的类型示例化模板,则将收到编译时错误。