C++ 任何类中的模板构造函数与非模板构造函数
想象一下这样写: 问题是:我是否需要保护模板化构造函数(为了构造C++ 任何类中的模板构造函数与非模板构造函数,c++,C++,想象一下这样写: 问题是:我是否需要保护模板化构造函数(为了构造任何而不受某些值的影响),或者我可以离开它,因为非模板(复制/移动)构造函数将始终与任何匹配?如果可能的话,volatile修饰符或者一些奇怪的std::move((const any&)it)呢 回答描述为构造函数的搜索将是非常感激的,谢谢你 编辑:构建包含另一个any的any将是一个问题,我明确希望避免这种情况(SFINAE确保它不会发生)。作为一般规则,如果模板函数和非模板函数在其他方面同样匹配良好,选择非模板版本而不是模板版
任何
而不受某些值的影响),或者我可以离开它,因为非模板(复制/移动)构造函数将始终与任何
匹配?如果可能的话,volatile
修饰符或者一些奇怪的std::move((const any&)it)
呢
回答描述为构造函数的搜索将是非常感激的,谢谢你
编辑:构建包含另一个
any
的any
将是一个问题,我明确希望避免这种情况(SFINAE确保它不会发生)。作为一般规则,如果模板函数和非模板函数在其他方面同样匹配良好,选择非模板版本而不是模板版本。由于您的any
copy/move构造函数是非模板的,因此对于右值或常量左值,它们优先于模板构造函数
但是由于右值引用模板的特殊规则,模板的推导类型为any(ValueType&&)
将是任何&
哪一个更匹配。因此,在复制非常量左值时,将调用模板化构造函数
因此,您需要该模板化构造函数的SFINAE规则,但不需要该模板化构造函数对常量进行左值引用。对于C++11和通用引用(以及具有此类参数的构造函数)的引入,重载解析规则将选择模板化版本 事实是,如果编译器可以在模板函数和非模板函数之间进行选择,那么它将使用非模板函数。但只有当它们同样好时,它才会这样做: §13.3.3最佳可行功能
[over.match.Best]
any(const any &);
template <typename ValueType>
any(const ValueType &);
a
的计算类型是左值任意&
,不带常量
修饰符。生成重载解析的候选构造函数集后,编译器将以以下签名结束:
any(const any &); // non-template
any(any &); // instantiated template
然后:
§13.3.1候选函数和参数列表[over.match.funcs]
const any a; // const!
any b{a};
那么这一次,从采用通用引用的构造函数生成的构造函数签名将与copy constructor的非模板版本相同,因此只调用非模板版本
如果可能的话,关于volatile修饰符或者一些奇怪的std::move((const any&)it)呢
同样的情况也会发生。通用引用构造函数是更好的匹配。
也就是说,std::move((const any&)it)
计算为const any&
类型的表达式
非模板移动构造函数的参数可以采用非常量值引用(因此根本不匹配,因为它缺少const
修饰符)
非模板复制构造函数的参数可以采用const-lvalue引用(也就是说,const-lvalue可以被const-lvalue引用绑定,但不是完全匹配的)
然后,采用通用引用的实例化模板再次是一个更好的匹配,将被调用。这就是我的想法,感谢您的澄清。使用SFINAE防止匹配任何或任何修改仍然是一个好主意吗?在这种情况下,模板化的构造函数可能会更好地匹配。。。这是我以前不知道的右值引用模板规则的副作用。。。我将相应地更新我的答案。两个构造函数模板都不需要。第二个已经在使用通用引用了。@dyp:嗯,起初我的问题中没有常量,但有人有一些抱怨。。。关于可读性。Boost::任何一个都有。谢谢你的回答,我可能会接受。我对模板化构造函数的错误感觉是正确的,谢谢你的解释。
any(const any &);
template <typename ValueType>
any(ValueType &&);
any a;
any b{a};
any(const any &); // non-template
any(any &); // instantiated template
const any a; // const!
any b{a};