C++ 基于继承类的模板特化
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/281725/
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
Template specialization based on inherit class
提问by
I want to make this specialized w/o changing main. Is it possible to specialize something based on its base class? I hope so.
我想让这个专门的不改变主。是否可以根据其基类专门化某些东西?但愿如此。
-edit-
-编辑-
I'll have several classes that inherit from SomeTag. I don't want to write the same specialization for each of them.
我将有几个继承自 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;
}
采纳答案by Jesse Beder
This article describes a neat trick: http://www.gotw.ca/publications/mxc++-item-4.htm
这篇文章描述了一个巧妙的技巧:http: //www.gotw.ca/publications/mxc++-item-4.htm
Here's the basic idea. You first need an IsDerivedFrom class (this provides runtime and compile-time checking):
这是基本的想法。您首先需要一个 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; }
};
Then your MyClass needs an implementation that's potentially specialized:
然后您的 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;
};
and MyClass actually looks like:
而 MyClass 实际上看起来像:
template<typename T>
class MyClass: public MyClassImpl<T, IsDerivedFrom<T, SomeTag>::Is>
{
};
Then your main will be fine the way it is:
那么你的主要会像现在这样:
int main()
{
MyClass<SomeTag>::isSpecialized test1; //ok
MyClass<InheritSomeTag>::isSpecialized test2; //ok also
return 0;
}
回答by Carlo Wood
And the short version now, 2014, using C++-11:
现在的简短版本,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 */
}
回答by Johannes Schaub - litb
Well, the article in the answer above appeared in February 2002. While it works, today we know there are better ways. Alternatively, you can use enable_if
:
好吧,上面答案中的文章发表于 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 */
}
回答by Konrad Rudolph
In your case, the only way that I see would be to explicitly specialize MyClass
for InheritSomeTag
. However, the SeqAn paperproposes a mechanism called “template sublassing” that does what you want –?albeit with a different inheritance syntax, so the code isn't compatible with your current main
function.
在您的情况下,我看到的唯一方法是明确专门MyClass
针对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
}
This certainly looks strange and is very cumbersome but it allows a true inheritance mechanism with polymorphic functions that is executed at compile time. If you want to see this in action, have a look at some SeqAn examples.
这当然看起来很奇怪并且非常麻烦,但它允许使用在编译时执行的多态函数的真正继承机制。如果您想看到实际效果,请查看一些SeqAn 示例。
That being said, I believe that SeqAn is a special case and not many applications would profit from this extremely difficult syntax (deciphering SeqAn-related compiler errors is a real pain in the *ss!)
话虽如此,我相信 SeqAn 是一个特例,没有多少应用程序会从这种极其困难的语法中受益(破译 SeqAn 相关的编译器错误是 *ss 中的真正痛苦!)