簡體   English   中英

創建涉及不完整類型成員的“使用”聲明的最佳方法是什么?

[英]What is the best way to create a 'using' declaration involving members of incomplete types?

我有一個非常簡單的 CRTP 骨架結構,它在基類中只包含一個向量和一個私有訪問器。 CRTP 類中有一個輔助方法可以訪問它。

#include <vector>

template<typename T>
class CRTPType {

   // Will be used by other member functions.  Note it's private, 
   // so declval/decltype expressions outside of friends or this class 
   // cannot see it
   auto& _v() {
       return static_cast<T *>(this)->getV();
   }
};


class BaseType : public CRTPType<BaseType> {

    friend class CRTPType<BaseType>;

    std::vector<int> v;

    //For different base types this impl will vary
    auto& getV() { return v; }
};

到目前為止,一切都很好。 現在我想向CRTPType添加一個using聲明,這將是_v()返回的類型。 因此,理想情況下,可以執行以下操作:

template<typename T>
class CRTPType {

   //Will be used by other member functions
   auto& _v() {
       return static_cast<T *>(this)->getV();
   }

   using vtype = decltype(std::declval<CRTPType<T>>()._v());
};

問題是類型不完整,所以我不能在CRTPType中使用任何decltype / declval表達式。

有沒有一種干凈的方法可以盡可能少地破壞封裝? 理想情況下在 C++14 中,但如果有任何新的語言功能有幫助,我會很感興趣。

如果您不太關心using聲明的出現位置和准確方式,那么您可以在不做太多更改的情況下避免該問題,例如將using聲明放入嵌套類中:

template<typename T>
class CRTPType {

   //Will be used by other member functions
   auto& _v() {
       return static_cast<T *>(this)->getV();
   }

   struct nested {
     using vtype = decltype(std::declval<CRTPType<T>>()._v());
   };
};

原始代碼中的問題是using聲明是使用類模板專業化隱式實例化的, CRTPType<BaseType>的隱式實例化點在BaseType的定義之前,因為后者使用前者作為基類(這是必需的是完整的,因此被隱式實例化)。

另一方面,嵌套成員類被指定為使用類模板特化隱式實例化,而是僅在需要它們完成時才進行實例化。 換句話說, using聲明的實例化點現在將緊接在命名空間范圍聲明之前,該聲明實際上直接或間接地使用nested::vtype


另一種選擇是使using聲明成為模板:

template<typename T>
class CRTPType {

   //Will be used by other member functions
   auto& _v() {
       return static_cast<T *>(this)->getV();
   }

   template<typename U = T>
   using vtype = decltype(std::declval<CRTPType<U>>()._v());
};

成員模板也不能使用包含類模板特化來隱式實例化。 可能需要使用U = T構造,並且僅在using =中使用U 原因是如果右側的類型不依賴於模板參數,編譯器可以在模板定義后立即檢查是否可以實例化,這正是我們想要的不可能避免。 因此,該程序可能是格式錯誤的,如果只使用T ,則不需要診斷 (我真的不是 100% 確定這適用於此,但 Clang 確實在抱怨。)


另一種可能性是將using聲明移到類之外,在這種情況下,很明顯它不會被隱式實例化:

template<typename T>
class CRTPType;

template<typename T>
using CRTPType_vtype = decltype(std::declval<CRTPType<T>>()._v());

template<typename T>
class CRTPType {

   //Will be used by other member functions
   auto& _v() {
       return static_cast<T *>(this)->getV();
   }

};

使用嵌套類或命名空間的變體與封閉命名空間中的using聲明相結合,可以從外部隱藏附加名稱。


有了上述所有內容,您仍然需要注意CRTPType<BaseType>的實例化或BaseType的定義中沒有其他任何內容實際上間接使用vtype 如果發生這種情況,您可能會回到最初的問題,甚至可能取決於成員的聲明順序(盡管從技術上講這不是編譯器的標准符合行為)。


在任何情況下,您都需要將 BaseType 中的CRTPType<BaseType> BaseType friend ,或者將BaseType中的getV標記為public

暫無
暫無

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

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