簡體   English   中英

如何在另一個類模板中定義完全專用的類的構造函數

[英]How to define constructor of fully-specialized class within another class template

我有一個包含另一個類模板的類模板,內部模板有一個顯式的特化:

template <typename Outer>
struct ContainingClass {
  template <typename T>
  struct Rule {
    Rule(T value);

    // ... other members ...
  };

  template <>
  struct Rule<void> {
    Rule();

    // ... different members than the non-void Rule<T> ...
  };
};

我已經為泛型和專用Rule定義了構造函數:

template <typename Outer>
template <typename T>
ContainingClass<Outer>::Rule<T>::Rule(T value) { }

template <typename Outer>
ContainingClass<Outer>::Rule<void>::Rule() { }

但Clang不喜歡專門類的構造函數:

error: nested name specifier 'ContainingClass<Outer>::Rule<void>::' for declaration does not refer into a class, class template or class template partial specialization
ContainingClass<Outer>::Rule<void>::Rule() { }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^

我對此感到困惑,因為它“引用” ContainingClass<Outer> ,它一個類( ContainingClass類模板的一個實例)。 我懷疑我需要在語法中改變一些東西,但目前還不清楚是什么。 我該如何定義這個構造函數?

(如果我刪除ContainingClass並將Rule放在命名空間范圍內,它可以工作,但我需要在Rule中有其他依賴於Outer類型的東西。我可以給Rule自己的Outer模板參數,但這會讓事情變得更加尷尬使用這個類的代碼,所以我想盡可能避免它。我知道我可以在Rule類體內定義構造函數內聯,但我想理解為什么單獨的定義不起作用。)

如果它很重要,我在Ubuntu 19.04中使用Clang 8.0,在Mac上使用Apple的“clang-1001.0.46.4”。 (我也嘗試過Ubuntu的GCC 8.3,但由於GCC錯誤#85282 - 在非命名空間作用域中顯式特化“在struct Rule<void>本身的定義上,它在另一個地方失敗了。)

編輯澄清:我的錯誤不是在ContainingClass具有template <> struct Rule<void> 這是C ++ 14限制( 缺陷CWG 727 )的主題,它通過添加虛擬模板參數來解決,因此模板只是部分而不是完全專用。 我相信在C ++ 17中已經取消了限制,並且Rule類的特化本身在Clang中運行良好(盡管GCC有bug)。 所以我認為虛擬參數解決方法在這里不是正確的解決方案 - 但請告訴我,如果我錯了,並且在C ++ 17中仍存在限制。

您不能在命名空間作用域聲明模板的模板成員的特化成員。

為了避免這種限制,您可以使用c ++ 14及更早版本所必需的解決方法,其中包括使用部分特化而不是完全特化:

template <typename Outer>
struct ContainingClass {
  template <typename T,class=void>
  struct Rule {
    Rule(T value);

    // ... other members ...
  };

  template <class U>
  struct Rule<void,U> {
    Rule();

    // ... different members than the non-void Rule<T> ...
  };
};

template <typename Outer>
template <typename T, typename U>
ContainingClass<Outer>::Rule<T,U>::Rule(T value) { }

template <typename Outer>
template <typename U>
ContainingClass<Outer>::Rule<void,U>::Rule() { }

在C ++ 17中,仍然無法在命名空間范圍內聲明(模板的)類模板的特化成員(參見[temp.expl.spec] / 17) C ++ 14標准中存在相同的段落。

使用C ++ 17改變的是我們可以在封閉類模板定義中聲明成員的特化:

應在包含專用模板的命名空間中聲明顯式特化。[...]

可以在可以定義相應主模板的任何范圍內聲明顯式特化。[...]

暫無
暫無

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

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