简短的问题
如何在编译时检查(编辑:未实例化(类模板是否继承自 C++17 的第一个模板参数?
长问题
我想通过按以下方式构造一些东西来了解类模板是否继承自其(第一个(模板参数:
template<template<typename> class TemplateClass>
struct template_parameter_is_base_of
{
/* Implementation */
};
理想情况下,template_parameter_is_base_of
可以像这样使用:
template<typename T> struct WithParent : T { /* Implementation */ };
template<typename T> struct WoutParent : { /* Implementation */ };
static_assert(template_parameter_is_base_of<WithParent>::value); // Ok as expected since WithParent inherits from T
static_assert(template_parameter_is_base_of<WoutParent>::value); // Error as expected since WithParent doesn't inherit from T
我失败的尝试
我尝试实现template_parameter_is_base_of
:
struct Dummy {};
template<template<typename> class TemplateClass>
struct template_parameter_is_base_of
{
static constexpr bool value = std::is_base_of_v<Dummy, TemplateClass<Dummy>>;
};
。在这种情况下有效:
template<typename T>
struct A : T {
void work() { /* Irrelevant implementation */ }
};
static_assert(template_parameter_is_base_of<A>::value); // Passes because A inherits from its template parameter. Nice!
。但是,如果类模板具有带有override
说明符的方法,则失败:
template<typename T>
struct B : T {
void work() override { /* Irrelevant implementation */ }
};
static_assert(template_parameter_is_base_of<B>::value); // Fails, but I want it to pass because B inherits from its template parameter.
这就是我现在的想法
我想我已经用上面使用Dummy
的方法把自己画进了一个角落,因为如果TemplateClass
包含任何带有override
说明符的方法,则std::is_base_of_v
内TemplateClass<Dummy>
的类模板实例化将始终失败。
但是,我认为实现template_parameter_is_base_of
应该是可能的,因为编译器应该在编译时知道类模板是否继承自其模板参数。也许我错了。
最后的问题
是否可以从 C++17 开始实施template_parameter_is_base_of
?如果是,怎么能做到这一点?
但是,我认为实现
template_parameter_is_base_of
应该是可能的,因为编译器应该在编译时知道模板类是否继承自其模板参数。
模板本质上是一个参数化工具,用于制造某些C++构造:类、函数或变量。模板本身还不是它要制作的东西。类模板不会从任何内容继承,因为它还不是类。所以这个问题本身不是一个功能性的问题。
除此之外,还存在显式/部分模板专用化。即使基类模板确实继承了其第一个模板参数,也不能保证任何事情。您仍然不知道模板的任何特定WithParent<T>
实例化是否实际使用基本模板。用户可以轻松地针对特定类型进行WithParent
专用化,甚至可以对整个类型系列采用部分专用化。
你想要的不是C++可以支持的东西。如果你试图验证某些东西或防止某些滥用或其他什么,你将不得不以另一种方式去做。
如何在编译时检查类模板是否继承自 C++17 的第一个模板参数?
您的意思是,如果实例化的类模板继承自其第一个模板参数?
简单,使用std::is_base_of_v
:
template <typename T, /*other stuff goes here*/>
class A : /* classes which A inherits from */ { /* ... */}
template <typename T, /*other stuff goes here*/>
constexpr bool A_inherits_its_first_tempalte_param() {
return std::is_base_of_v<T, A<T, /* ... */ >;
}
就是这样。
不确定是否是一个好方法,但我建议您采用以下方式进行探索。
您可以尝试编写类型特征,如下所示
template <typename T>
void foo (T *);
template <template <typename> class, typename = void>
struct tp_is_base_of : public std::false_type
{ };
template <template <typename> class C>
struct tp_is_base_of<
C, std::void_t<decltype(foo<Dummy>(std::declval<C<Dummy>*>()))>>
: public std::true_type
{ };
通过这种方式,您可以检查等待Dummy
指针的函数是否接受C<Dummy>
指针:如果C<Dummy>
继承自Dummy
,答案应该是肯定的。
以下是完整的编译示例
#include <type_traits>
struct Dummy { virtual void work() {} };
template <typename T>
struct A : T
{ void work() { /* Irrelevant implementation */ } };
template <typename T>
struct B : T
{ void work() override { /* Irrelevant implementation */ } };
template <typename T>
struct C
{ };
template <typename T>
void foo (T *);
template <template <typename> class, typename = void>
struct tp_is_base_of : public std::false_type
{ };
template <template <typename> class C>
struct tp_is_base_of<
C, std::void_t<decltype(foo<Dummy>(std::declval<C<Dummy>*>()))>>
: public std::true_type
{ };
int main()
{
static_assert( true == tp_is_base_of<A>::value );
static_assert( true == tp_is_base_of<B>::value );
static_assert( false == tp_is_base_of<C>::value );
}