[英]Template specialization based on inherit class
我想把这个专门化,不改变主线。 是否可以根据其基础 class 专门化某些东西? 但愿如此。
-编辑-
我将有几个继承自 SomeTag 的类。 我不想为他们每个人写相同的专业。
class SomeTag {};
class InheritSomeTag : public SomeTag {};
template <class T, class Tag=T>
struct MyClass
{
};
template <class T>
struct MyClass<T, SomeTag>
{
typedef int isSpecialized;
};
int main()
{
MyClass<SomeTag>::isSpecialized test1; //ok
MyClass<InheritSomeTag>::isSpecialized test2; //how do i make this specialized w/o changing main()
return 0;
}
本文介绍了一个巧妙的技巧: http : //www.gotw.ca/publications/mxc++-item-4.htm
这是基本的想法。 首先需要一个IsDerivedFrom类(这提供了运行时和编译时检查):
template<typename D, typename B>
class IsDerivedFrom
{
class No { };
class Yes { No no[3]; };
static Yes Test( B* ); // not defined
static No Test( ... ); // not defined
static void Constraints(D* p) { B* pb = p; pb = p; }
public:
enum { Is = sizeof(Test(static_cast<D*>(0))) == sizeof(Yes) };
IsDerivedFrom() { void(*p)(D*) = Constraints; }
};
那么你的MyClass需要一个可能专门的实现:
template<typename T, int>
class MyClassImpl
{
// general case: T is not derived from SomeTag
};
template<typename T>
class MyClassImpl<T, 1>
{
// T is derived from SomeTag
public:
typedef int isSpecialized;
};
和MyClass实际上看起来像:
template<typename T>
class MyClass: public MyClassImpl<T, IsDerivedFrom<T, SomeTag>::Is>
{
};
然后你的主要将是好的方式:
int main()
{
MyClass<SomeTag>::isSpecialized test1; //ok
MyClass<InheritSomeTag>::isSpecialized test2; //ok also
return 0;
}
好吧,上面答案中的文章出现在2002年2月。虽然它有效,但今天我们知道有更好的方法。 或者,您可以使用enable_if
:
template<bool C, typename T = void>
struct enable_if {
typedef T type;
};
template<typename T>
struct enable_if<false, T> { };
template<typename, typename>
struct is_same {
static bool const value = false;
};
template<typename A>
struct is_same<A, A> {
static bool const value = true;
};
template<typename B, typename D>
struct is_base_of {
static D * create_d();
static char (& chk(B *))[1];
static char (& chk(...))[2];
static bool const value = sizeof chk(create_d()) == 1 &&
!is_same<B volatile const,
void volatile const>::value;
};
struct SomeTag { };
struct InheritSomeTag : SomeTag { };
template<typename T, typename = void>
struct MyClass { /* T not derived from SomeTag */ };
template<typename T>
struct MyClass<T, typename enable_if<is_base_of<SomeTag, T>::value>::type> {
typedef int isSpecialized;
};
int main() {
MyClass<SomeTag>::isSpecialized test1; /* ok */
MyClass<InheritSomeTag>::isSpecialized test2; /* ok */
}
现在是2014年的短版本,使用C ++ - 11:
#include <type_traits>
struct SomeTag { };
struct InheritSomeTag : SomeTag { };
template<typename T, bool = std::is_base_of<SomeTag, T>::value>
struct MyClass { };
template<typename T>
struct MyClass<T, true> {
typedef int isSpecialized;
};
int main() {
MyClass<SomeTag>::isSpecialized test1; /* ok */
MyClass<InheritSomeTag>::isSpecialized test2; /* ok */
}
在您的情况下,我看到的唯一方法是显式专门化MyClass
for InheritSomeTag
。 但是, SeqAn论文提出了一种称为“模板子类”的机制,它可以做你想要的 - 尽管有不同的继承语法,所以代码与你当前的main
函数不兼容。
// Base class
template <typename TSpec = void>
class SomeTag { };
// Type tag, NOT part of the inheritance chain
template <typename TSpec = void>
struct InheritSomeTag { };
// Derived class, uses type tag
template <typename TSpec>
class SomeTag<InheritSomeTag<TSpec> > : public SomeTag<void> { };
template <class T, class Tag=T>
struct MyClass { };
template <class T, typename TSpec>
struct MyClass<T, SomeTag<TSpec> >
{
typedef int isSpecialized;
};
int main()
{
MyClass<SomeTag<> >::isSpecialized test1; //ok
MyClass<SomeTag<InheritSomeTag<> > >::isSpecialized test2; //ok
}
这当然看起来很奇怪并且非常麻烦,但它允许使用在编译时执行的多态函数的真正继承机制。 如果你想看到这个,请看看一些SeqAn例子 。
话虽这么说,我相信SeqAn是一个特例,没有多少应用程序可以从这个极其困难的语法中获益(解密SeqAn相关的编译器错误是* ss真正的痛苦!)
使用 C++20 中的概念和 requires 关键字是一种更简单、更具表现力的方法,无需像 C++11 那样引入冗余的 boolean 非类型模板参数:
// C++20:
#include <concepts>
#include <iostream>
struct SomeTag { };
struct InheritSomeTag : SomeTag { };
template<typename T>
struct MyClass
{
void Print()
{
std::cout << "Not derived from someTag\n";
}
};
// std::derived_from is a predefined concept already included in the STL
template<typename T>
requires std::derived_from<T, SomeTag>
struct MyClass<T>
{
void Print()
{
std::cout << "derived from someTag\n";
}
};
int main()
{
MyClass<InheritSomeTag> test1;
test1.Print(); // derived from someTag
MyClass<int> test2;
test2.Print(); // Not derived from someTag
// Note how even the base tag itself returns true from std::derived_from:
MyClass<SomeTag> test3;
test3.Print(); // derived from someTag
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.