簡體   English   中英

禁用模板化類中的函數

[英]Disable functions inside templated class

我試圖在一個簡單的模板類中禁用一些函數。 應刪除的函數取決於模板參數是否具有某些typedef。

這個例子歸結為:

template<typename T>
struct Foo
{
  typename T::Nested foo() { return typename T::Nested(); }
  int bar() { return 1; }
};


struct NoNested
{
};

struct WithNested
{
  typedef int Nested;
};

int main()
{
  Foo<WithNested> fwn;
  fwn.foo();
  fwn.bar();

  Foo<NoNested> fnn;
  //fnn.foo();
  fnn.bar();
}

但是這給了我一個error: no type named 'Nested' in 'struct NoNested'在gcc和clang ++上的error: no type named 'Nested' in 'struct NoNested'樣式錯誤中error: no type named 'Nested' in 'struct NoNested' (請注意兩者的舊版本)。

當typedef T::Nested沒有退出時,是否有一種簡單的方法來刪除foo (除了Foo<T>類的模板特化之外,在實際代碼中我有大約5個具有不同typedef的函數...這將導致2 ^ 5個不同的特化)

編輯:因為有一些人要求這樣做的動機:我想創建類似於編譯時間FSM的東西,以便在DSL中使用。

我希望能夠做到這一點

struct StateA;
struct StateB;
struct StateC;

struct StateA
{
  typedef StateB AfterNext;
};

struct StateB
{
   typedef StateA AfterPrev;
   typedef StateC AfterNext;
};

struct StateC
{
   typedef StateB AfterPrev;
};

template<typename T>
struct FSM
{
   FSM<typename T::AfterNext> next() { return FSM<T::AfterNext>(); };
   FSM<typename T::AfterPrev> prev() { return FSM<T::AfterPrev>(); };
};

以便

FSM<StateA>().next().prev().next().next();

編譯但是

FSM<StateA>().next().prev().prev();

失敗。

注意,實際上會有比這更多的轉換函數,轉換函數實際上會做一些事情,而FSM會存儲一些狀態。

更新 :我已經使用到目前為止給出的方法創建了適當的示例 答案的復雜程度各不相同,雖然訪問者方法是我可能最終使用的方法(因為它最簡單),但我的解決方案(最復雜的)是唯一一個實際刪除該功能的方法。

您可以使用類模板專門化。 如果您有多個函數,則可以將每個函數移動到基類,並專門化每個基類。

嘗試自己制作函數foo模板。 它只會在被調用時編譯,因此只有在嘗試使用NoNested類調用它時才會出現錯誤。

您可以向每個類添加嵌套的typedef,這樣只有在實例化函數時編譯才會失敗。

struct null_type;  //an incomplete type, you could use a more descriptive name for your particular problem

template<typename T>
struct Foo
{
  typename T::Nested foo() { return typename T::Nested(); }
  int bar() { return 1; }
};


struct NoNested
{
   typedef null_type Nested;
};

struct WithNested
{
  typedef int Nested;
};

int main()
{
  Foo<WithNested> fwn;
  fwn.foo();
  fwn.bar();

  Foo<NoNested> fnn;
  //fnn.foo();  //attempt to use incomplete type when used
  fnn.bar();
}

可以選擇類型T::Nested (如果存在),否則為void ,如下所示。

默認選擇為void

template<class T, class = void>
struct NestedReturn
{
  typedef void type;
};

一個總是返回void模板,無論你給它什么類型:

template<class T>
struct Void
{
  typedef void type;
};

SFINAE對具有Nested嵌套類的類型的特化。 請注意, typename Void<typename T::Nested>::type始終為void,以匹配基本模板中void的默認第二個參數:

template<class T>
struct NestedReturn<T, typename Void<typename T::Nested>::type>
{
  typedef typename T::Nested type;
};

現在我們使用它。 請注意,當沒有T::Nested ,實際上不會刪除foo() ,但實例化它會導致錯誤。

template<typename T>
struct Foo
{
  typename NestedReturn<T>::type foo() { return typename T::Nested(); }
  int bar() { return 1; }
};


struct NoNested
{
};

struct WithNested
{
  typedef int Nested;
};

int main()
{
  Foo<WithNested> fwn;
  fwn.foo();
  fwn.bar();

  Foo<NoNested> fnn;
  //fnn.foo();
  fnn.bar();
}

我懷疑使用默認的函數模板參數可以正確地使用SFINAE刪除foo() ,但這只能在C ++ 11中進行(未經測試的猜測):

template<typename T>
struct Foo
{
  template<class N = T::Nested>
  N foo() { return N(); }
  int bar() { return 1; }
};

以下是我認為我可以解決的問題。 它的靈感來自user763305的評論。 它需要2 * N的專業而不是2 ^ N。

template <typename T>
struct has_nested {
  // Variables "yes" and "no" are guaranteed to have different sizes,
  // specifically sizeof(yes) == 1 and sizeof(no) == 2.
  typedef char yes[1];
  typedef char no[2];

  template <typename C>
    static yes& test(typename C::Nested*);

  template <typename>
    static no& test(...);

  // If the "sizeof" the result of calling test<T>(0) would be equal to the sizeof(yes),
  // the first overload worked and T has a nested type named type.
  static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};



template<typename T>
struct FooBase
{
  int bar() { return 1; }
};

template<typename T, bool>
struct FooImpl : public FooBase<T>
{
};

template<typename T>
struct FooImpl<T,true> : public FooBase<T>
{
  typename T::Nested foo() { return typename T::Nested(); }
};


template<typename T>
struct Foo : public FooImpl<T, has_nested<T>::value >
{
};


struct NoNested
{
};

struct WithNested
{
  typedef int Nested;
};

int main()
{
  Foo<WithNested> fwn;
  fwn.foo();
  fwn.bar();

  Foo<NoNested> fnn;
  //fnn.foo();
  fnn.bar();

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM