簡體   English   中英

類any中的模板構造函數與非模板構造函數

[英]Template constructor vs. non-template constructor in class any

想象一下像boost::any這樣的東西:

class any {
public:
  any();
  any(const any &);
  any(any &&);
  template<typename ValueType> any(const ValueType &);
  template<typename ValueType> any(ValueType &&);

是否會為任何可能的any調用適當的(復制/移動)構造函數? 或者它必須與SFINAE一起編寫,例如:

template<typename ValueType,
  typename = typename std::enable_if<
    !std::is_same<any, typename std::decay<ValueType>::type>::value
  >::type>
  any(const ValueType& value)
template<typename ValueType,
  typename = typename std::enable_if<
    !std::is_same<any, typename std::decay<ValueType>::type>::value
  >::type>
  any(ValueType&& value)

問題是:我是否需要保護模板化構造函數(從某個值構造any值)或者我可以保留它,因為非模板(復制/移動)構造函數將始終匹配any 如果可能的話,那么volatile修飾符或一些奇​​怪的std::move((const any&)it)怎么樣?

謝謝你說,描述搜索構造函數的答案最為貼切。

編輯:構建any包含另一個any將是一個問題,我definitelly想要避免(SFINAE確保它不會發生)。

使用C ++ 11並引入Universal Reference (以及具有此類參數的構造函數),重載決策的規則將選擇模板化版本。

事實是,如果編譯器可以在模板化和非模板化函數之間進行選擇,那么它將與非模板一起使用。 只有當它們同樣好的時候會這樣做:

[over.match.best]最佳可行功能[over.match.best]

  1. [...]鑒於這些定義,如果對於所有參數i ,ICS i (F1) 不是比ICS i (F2) 更差的轉換序列,則可行函數F1被定義為比另一個可行函數F2更好的函數,並且然后

    - 對於某些參數j ,ICS j (F1)是比ICS j (F2) 更好的轉換序列,或者, 如果不是

    [...]

    - F1是非模板功能,F2是功能模板專業化,[...]

也就是說,有兩個構造函數聲明如下:

any(const any &);

template <typename ValueType>
any(const ValueType &);

編譯器將選擇非模板 版本,因為實例化模板版本會產生完全相同的聲明

但是,隨着構造函數采用Unviersal Reference ,情況會發生根本變化:

any(const any &);

template <typename ValueType>
any(ValueType &&);

在使用常規直接初始化語法復制實例的上下文中:

any a;
any b{a};

的評價類型a是一個左值any & 而不 const改性劑。 在生成用於重載解析的候選構造函數集之后,編譯器最終得到以下簽名:

any(const any &); // non-template

any(any &); // instantiated template

接着:

[over.match.funcs]候選函數和參數列表[over.match.funcs]

  1. 在候選者是函數模板的每種情況下,使用模板參數推導(14.8.3,14.8.2)生成候選函數模板特化。 然后以通常的方式將這些候選人作為候選職能處理。 給定名稱可以引用一個或多個函數模板,也可以引用一組重載的非模板函數。 在這種情況下,從每個功能模板生成的候選函數與該組非模板候選函數組合。

也就是說, 模板版本是更好的匹配 ,這是編譯器選擇的。

但是,如果有人:

const any a; // const!
any b{a};

那么這次從構造函數生成的構造函數簽名采用Universal Reference將與copy-constructor的非模板版本相同,因此只有非模板版本被調用。

如果可能的話,那么volatile修飾符或一些奇​​怪的std :: move((const any&))怎么樣?

完全相同的情況發生。 Universal Reference構造函數是一個更好的匹配。

也就是說, std::move((const any&)it)計算為const any && type的表達式。

非模板移動構造函數的參數可以采用非const rvalue引用 (因此根本不匹配,因為它缺少const修飾符)。

非模板復制構造函數的參數可以采用const左值引用 (很好,const rvalue可以通過const lvalue引用綁定,但不是完全匹配 )。

然后,采用通用引用的實例化模板再次是將被調用的更好匹配。

作為一般規則,如果模板和非模板函數在其他方面同樣匹配,則在模板版本上選擇非模板版本。 由於您的any復制/移動構造函數都是非模板,因此對於rvalues或常量左值,它們優先於模板構造函數。

但是感謝rvalue引用模板的特殊規則, template<typename ValueType> any(ValueType &&);的推導類型template<typename ValueType> any(ValueType &&); 將是any& 更好的匹配。 因此,在復制非const左值時,您將調用模板化構造函數。

因此,對於該模板化構造函數,您需要一個SFINAE規則,但對於采用左值引用const的模板化構造函數則不需要。

暫無
暫無

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

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