簡體   English   中英

嵌套類聲明:模板與非模板外部類

[英]Nested class declaration: template vs non-template outer class

我有一個c ++模板類,里面有一個嵌套類,如:

template<int d>
class Outer_t
{
public:
    class Inner;

    Inner i;
};

template<int d>
class Outer_t<d>::Inner
{
public:
    float x;
};

int main ()
{
    Outer_t<3> o_t; // 3 or any arbitrary int
    o_t.i.x = 1.0;

  return 0;
}

這編譯沒有任何問題。 但是,只要我聲明一個類似的非模板類,就像這樣:

class Outer_1
{
public:
    class Inner;

    Inner i;
};

class Outer_1::Inner
{
public:
    float x;
};

int main ()
{
    Outer_1 o1;
    o1.i.x = 1.0;

  return 0;
}

我開始收到以下錯誤(我正在使用gcc 4.6.3):“錯誤:字段'我'的類型不完整”。 我知道我可以通過在外部類中定義內聯類內聯來解決這個問題:

class Outer_2
{
public:
    class Inner {
    public:
        float x;
    };

    Inner i;
};

這將編譯,但我想避免定義嵌套類內聯。 所以我有兩個問題:模板與非模板嵌套類聲明之間存在明顯奇怪差異的原因是什么? 是否有一種優雅的方式來聲明和使用外部類中的nester類,同時避免將其定義為內聯,與模板類的風格大致相同? 在此先感謝您的幫助!

為什么編譯錯誤?

編譯器需要知道成員變量類型的大小才能進行對象布局。 對於Outer_1 ,因為Inner只是一個前向聲明,我們不知道它的大小。 因此編譯錯誤。 但是對於Outer_2 ,定義是內聯的,所以當我們到達Inner類型的成員變量時,我們知道它的大小。

為什么模板會通過?

另一方面,類模板在模板實例化發生之前不會被定義。 在您的示例中, 隱式實例化發生在main 那時, Inner的定義是完整的,因此它的大小是已知的。 通過在Inner的定義之前使用顯式實例化,我們可以看到這種情況。

 template<int d>
 class Outer_t
 {
 public:
     class Inner;

     Inner i;
 };

 template class Outer_t<3>;  // explicit instantation

 template<int d>
 class Outer_t<d>::Inner
 {
 public:
     float x;
 };

 int main ()
 {
     Outer_t<3> o_t; // 3 or any arbitrary int
     o_t.i.x = 1.0;

   return 0;
 }

Clang產生以下錯誤:

 a.cc:7:11: error: implicit instantiation of undefined member 'Outer_t<3>::Inner'
     Inner i;
           ^
 a.cc:10:16: note: in instantiation of template class 'Outer_t<3>' requested here
 template class Outer_t<3>;
           ^
 a.cc:5:11: note: member is declared here
     class Inner;
           ^

解決方案

如果你想提取嵌套類的定義,我建議的解決方案是讓它像Outer_t一樣進行模板化,但為方便起見提供別名。

 template <typename Dummy = void>
 class Outer_1_Impl {
   public:

   class Inner;

   Inner i;
 };

 template <typename Dummy>
 class Outer_1_Impl<Dummy>::Inner {
   public:
   float x;
 };

 using Outer_1 = Outer_1_Impl<>;

 int main () {
   Outer_1 o1;
   o1.i.x = 1.0;
 }

在定義類時,只能在對象中具有完整定義的非靜態成員。 在你的非模板示例中, Outer_1::Inner顯然不完整,因為它只是聲明到目前為止。 創建Inner的成員的唯一方法是確定它就像為Outer_2所做的Outer_2

現在,為什么使用類模板時不會出現問題? 答案是:當你在main()中實例化Outer_t時,實際上一個Outer_t<T>::Inner可訪問的完整定義! ...並且在使用某種類型T實例化Outer_t<T>之前,並不真正需要Outer_t的定義。

暫無
暫無

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

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