基于继承类的模板特化

发布于 2024-07-09 09:11:45 字数 550 浏览 5 评论 0原文

我想让这个专业化而不改变主要。 是否有可能根据其基类来专门化某些东西? 但愿如此。

-编辑-

我将有几个继承自 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;
}

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.

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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

情归归情 2024-07-16 09:11:46

使用 C++20 中的概念和 require 关键字是一种更简单、更具表现力的方法,而无需像 C++11 中那样引入冗余的布尔非类型模板参数:

// 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 

}

Using concepts and the requires keyword from C++20 is an even simpler and more expressive way to do this without having to introduce a redundant boolean non-type template parameter like in C++11:

// 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 

}
孤独岁月 2024-07-16 09:11:45

使用 C++-20 更新概念:

#include <concepts>

struct NotSomeTag { };
struct SomeTag { };
struct InheritSomeTag : SomeTag { };

template<typename T>
concept ConceptSomeTag = std::is_base_of_v<SomeTag, T>;

template<class T>
struct MyClass {
};

// Specialization.
template<ConceptSomeTag ST>
struct MyClass<ST> {
    using isSpecialized = int;
};

int main() {
    MyClass<SomeTag>::isSpecialized test1;        /* ok */
    MyClass<InheritSomeTag>::isSpecialized test2; /* ok */
    MyClass<NotSomeTag>::isSpecialized test3;     /* fail */
}

我 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 */
}

Update for concepts, using C++-20:

#include <concepts>

struct NotSomeTag { };
struct SomeTag { };
struct InheritSomeTag : SomeTag { };

template<typename T>
concept ConceptSomeTag = std::is_base_of_v<SomeTag, T>;

template<class T>
struct MyClass {
};

// Specialization.
template<ConceptSomeTag ST>
struct MyClass<ST> {
    using isSpecialized = int;
};

int main() {
    MyClass<SomeTag>::isSpecialized test1;        /* ok */
    MyClass<InheritSomeTag>::isSpecialized test2; /* ok */
    MyClass<NotSomeTag>::isSpecialized test3;     /* fail */
}

My post from 2014, using 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 */
}
萌︼了一个春 2024-07-16 09:11:45

本文描述了一个巧妙的技巧: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>
{
};

然后您的 main 就可以了:

int main()
{
    MyClass<SomeTag>::isSpecialized test1; //ok
    MyClass<InheritSomeTag>::isSpecialized test2; //ok also
    return 0;
}

This article describes a neat trick: 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):

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:

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:

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;
}
东京女 2024-07-16 09:11:45

嗯,上面答案中的文章发表于 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 */
}

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:

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 */
}
丑疤怪 2024-07-16 09:11:45

就您而言,我看到的唯一方法是显式专门化 MyClassInheritSomeTag。 然而,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 中真正的痛苦!)

In your case, the only way that I see would be to explicitly specialize MyClass for InheritSomeTag. However, the SeqAn paper proposes 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.

// 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.

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!)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文