我有这种代码
template <typename D, typename T>
class tl1 {
std::list<T> mTs ;
public:
T & getTbyName() const ;
}
template <typename T, typename C>
class tl2 {
public:
std::string getName() { return mName ; }
private:
C & mC ;
std::string mName
}
class c2 ;
class cl1 : tl1<cl1, cl2> {
}
class cl2 : tl2<cl2, cl1> {
}
我如何检查(compile time
)T
cl2
类型或derived from cl2
和C
是cl1
类型还是{{ 1}}。我需要确定cl2类型或derived from cl1
将是一团糟。
感谢您的时间 昆汀
答案 0 :(得分:6)
您可以使用static_assert
和std::is_base_of
。
#include <type_traits>
struct B {};
template <typename T>
class C {
static_assert(std::is_base_of<B, T>::value, "T should inherit from B");
};
struct D : public B {};
struct KO {};
template class C<B>;
template class C<D>;
template class C<KO>;
int main()
{
}
main.cpp: In instantiation of 'class C<KO>':
main.cpp:16:16: required from here
main.cpp:7:5: error: static assertion failed: T should inherit from B
static_assert(std::is_base_of<B, T>::value, "T should inherit from B");
^
======= clang =======
main.cpp:7:5: error: static_assert failed "T should inherit from B"
static_assert(std::is_base_of<B, T>::value, "T should inherit from B");
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:16:16: note: in instantiation of template class 'C<KO>' requested here
template class C<KO>;
^
答案 1 :(得分:1)
使用std::is_base_of
中的<type_traits>
和std::enable_if
:
template <typename T,
typename = typename std::enable_if<std::is_base_of<cl2, T>::value>::type>
class cl1 {
std::list<T> mTs ;
}
答案 2 :(得分:1)
当你想弄清楚A是否是B的基础时,你的编译器需要知道类型定义,或者A和B必须是相同的(A是A的基础)。
因此,您要检查一个模板参数是否来自前向声明的类型。
从您的later post判断,您还需要检查您的CRTP基类是否实际用作其中一个参数的基类。
在后一种情况下,编译器在CRTP基类专用时没有所有信息,因为尚未定义派生类。
因此,您必须将评估推迟到编译器具有必要信息的后期阶段。为此,让我们创建一个帮助器:
#include <utility>
class cl2;
class cl1;
template <typename Defer, typename Base, typename Derived>
struct deferred_is_base_of : std::is_base_of<Base, Derived>
{
};
理论上,这个类可以在以后专门化,因此编译器不能假设defered_is_base_of
与std::is_base_of
相同。
假设我们需要一个构造函数(任何其他“必需”函数也可以):
template <typename Derived, typename Value>
class tl1
{
public:
template <typename Defer = void>
tl1()
{
static_assert(deferred_is_base_of<Defer, cl2, Value>::value,
"Value has to be derived from cl2");
static_assert(deferred_is_base_of<Defer, tl1, Derived>::value,
"Derived has to be derived from tl1");
}
};
构造函数是一个带有默认参数的模板。因此,您可以像往常一样调用它。但编译器必须等待您这样做,因为可能使用不同的模板参数。
这就是诀窍。只有在调用构造函数时,编译器才会评估静态断言。到那时,将有足够的信息。
第二个模板的工作方式相同:
template <typename Derived, typename Value>
class tl2
{
public:
template <typename Defer = void>
tl2()
{
static_assert(deferred_is_base_of<Defer, cl1, Value>::value,
"Value has to be derived from cl1");
static_assert(deferred_is_base_of<Defer, tl2, Derived>::value,
"Derived has to be derived from tl2");
}
};
class cl1 : tl1<cl1, cl2>
{
cl1()
{
}
};
class cl2 : tl2<cl2, cl1>
{
cl2()
{
}
};
int main() {}
推迟模板评估是TMP工具箱中的一个强大工具。
编辑: 正如@Brandon指出的那样,此处不需要延迟基数。只需将检查放入构造函数中即可推迟。