类any中的模板构造函数与非模板构造函数

fir*_*rda 3 c++

想象一下写下这样的东西boost::any:

class any {
public:
  any();
  any(const any &);
  any(any &&);
  template<typename ValueType> any(const ValueType &);
  template<typename ValueType> any(ValueType &&);
Run Code Online (Sandbox Code Playgroud)

是否可以调用适当的(复制/移动)构造函数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)
Run Code Online (Sandbox Code Playgroud)

问题是:我是否需要保护模板化构造函数(any从某个值构造)或者我可以保留它,因为非模板(复制/移动)构造函数将始终匹配any?怎么样volatile修改或者一些奇怪的std::move((const any&)it),如果这是可能的吗?

谢谢你说,描述搜索构造函数的答案最为贴切.

编辑:构建any包含另一个any将是一个问题,我definitelly想要避免(SFINAE确保它不会发生).

Pio*_*cki 7

使用C++ 11并引入Universal Reference(以及具有此类参数的构造函数),重载决策的规则将选择模板化版本.

事实是,如果编译器可以在模板化和非模板化函数之间进行选择,那么它将与非模板一起使用.但只有当它们同样好的时候会这样做:

§13.3.3最佳可行功能 [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 &);
Run Code Online (Sandbox Code Playgroud)

编译器将选择非模板版本,因为实例化模板版本会产生完全相同的声明.

但是,随着构造函数采用Unviersal Reference,情况会发生根本变化:

any(const any &);

template <typename ValueType>
any(ValueType &&);
Run Code Online (Sandbox Code Playgroud)

在使用常规直接初始化语法复制实例的上下文中:

any a;
any b{a};
Run Code Online (Sandbox Code Playgroud)

的评价类型a是一个左值any & 而不const改性剂.在生成用于重载解析的候选构造函数集之后,编译器最终得到以下签名:

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

any(any &); // instantiated template
Run Code Online (Sandbox Code Playgroud)

然后:

§13.3.1候选函数和参数列表 [over.match.funcs]

  1. 在候选者是函数模板的每种情况下,使用模板参数推导(14.8.3,14.8.2)生成候选函数模板特化.然后以通常的方式将这些候选人作为候选职能处理.给定名称可以引用一个或多个函数模板,也可以引用一组重载的非模板函数.在这种情况下,从每个功能模板生成的候选函数与该组非模板候选函数组合.

也就是说,模板版本是更好的匹配,这是编译器选择的.

但是,如果有人:

const any a; // const!
any b{a};
Run Code Online (Sandbox Code Playgroud)

那么这次从构造函数生成的构造函数签名采用Universal Reference将与copy-constructor的非模板版本相同,因此只有非模板版本被调用.

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

完全相同的情况发生.该通用参考构造函数是一个更好的匹配.

也就是说,std::move((const any&)it)评估const any &&类型的表达.

非模板移动构造函数的参数可以采用非const rvalue引用(因此根本不匹配,因为它缺少const修饰符).

非模板复制构造函数的参数可以采用const左值引用(很好,const rvalue可以通过const lvalue引用绑定,但不是完全匹配).

然后,实例化的模板以通用参考一次更好的匹配会被调用.