Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/130.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 任何类中的模板构造函数与非模板构造函数_C++ - Fatal编程技术网

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]
  • […]根据这些定义,可行函数F1被定义为比另一个可行函数更好的函数 如果对于所有参数i,ICSi(F1)的转换顺序不比ICSi(F2)差,则

    -对于某些参数j,ICSj(F1)是比ICSj(F2)更好的转换序列,或者,如果不是那样的话,

    [……]

    -F1是非模板函数,F2是函数模板专用化,[…]

  • 也就是说,有两个构造函数声明如下:

    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]
  • 在每种情况下,如果候选函数是函数模板,则使用模板参数推断(14.8.3、14.8.2)生成候选函数模板专门化然后,这些候选函数将按常规方式作为候选函数处理。给定名称可以引用一个或多个函数模板,也可以引用一组重载的非模板函数。在这种情况下,从每个函数模板生成的候选函数与非模板候选函数集相结合
  • 也就是说,模板版本更匹配,这是编译器选择的

    但是,如果有:

    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};