[英]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]
[...]鑒於這些定義,如果對於所有參數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]
- 在候選者是函數模板的每種情況下,使用模板參數推導(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.