繁体   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