25

これをメインに変えずに特化させたい。基本クラスに基づいて何かを特殊化することは可能ですか? そうだといい。

-編集-

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

4 に答える 4

23

この記事では、巧妙なトリックについて説明します: 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;
}
于 2008-11-11T18:57:04.810 に答える
23

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 */
}
于 2014-09-19T12:42:45.307 に答える
21

上記の回答の記事は 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 */
}
于 2008-11-11T20:12:03.050 に答える
4

あなたの場合、私が見る唯一の方法は、明示的にに特化する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
}

これは確かに奇妙に見え、非常に面倒ですが、コンパイル時に実行されるポリモーフィック関数を使用した真の継承メカニズムを可能にします。これが実際に動作していることを確認したい場合は、SeqAnの例をいくつか見てください。

そうは言っても、SeqAnは特殊なケースであり、この非常に難しい構文から利益を得るアプリケーションは多くないと思います(SeqAn関連のコンパイラエラーを解読することは* ssの本当の苦痛です!)

于 2008-11-11T18:41:21.813 に答える