繁体   English   中英

为什么编译器在分配时调用模板化副本构造函数?

[英]Why does the compiler invoke a templated copy constructor when assigning?

考虑下面的代码:

#include <iostream>

template<class T>
struct X
{
    X() = default;

    template<class U>
    X(const X<U>&)
    {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }

/*
    template<class U>
    X& operator=(const X<U>&)
    {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
        return *this;
    }
*/

};

int main()
{
    X<int> a;
    X<double> b;

    b = a;
}

住在科利鲁

如您所见,赋值运算符已被注释掉。 但是,线

b = a;

编译良好。 我认为它不应该编译,因为ab具有不同的类型,并且编译器默认生成的operator=(const X&)将由基础类型实例化,因此不会分配X<int>X<double>

令我惊讶的是,代码已编译,并且似乎正在调用模板化副本构造函数。 为什么是这样? 难道是因为编译器会先尝试在投ab然后调用默认生成的B::operator=

如果TU是不同的类型,则template<class U> X(const X<U>&)不是复制构造函数,因为它的参数是不同类型的。 换句话说, X<int>X<double>是不相关的类型,因此此构造函数只是它们之间的用户定义转换。

请注意,此代码不会打印任何内容:

X<int> a;
X<int> b { a };

因为在这种情况下,将调用形式为X<int>::X(const X<int>&)的隐式声明的副本构造X<int>::X(const X<int>&)

编译器正在生成对X<double>(const X<int>&)的调用,以将X<int>转换为X<double> 然后调用生成的赋值运算符X<double>& X<double>::operator =(const X<double>&); 做作业。

如果您明确列出所有步骤,它将是:

b.operator =(X<double>(a));

template<class U> X(const X<U>&)是一种通用的用户定义转换-请参阅Anton Savin的答案。

隐式类型转换的规则非常复杂,因此您应警惕用户定义的转换函数(“ 更有效的C ++项目5” )。 模板功能更是如此。

编码

#include <iostream>

template<class T>
struct X
{
    X() = default;

    template<class U>
    X(const X<U>&)
    {
        std::cout << "generalized ctor: " << __PRETTY_FUNCTION__ << std::endl;
    }

/*
    template<class U>
    X& operator=(const X<U>&)
    {
        std::cout << "generalized assignment: " << __PRETTY_FUNCTION__ << std::endl;
        return *this;
    }
*/
};

int main()
{
    X<int> a;
    X<double> b;

    b = a;
}

回报

广义ctor:X :: X(const X&)[with U = int; T =两倍]

但是对于operator=未注释掉),它将返回

广义赋值:X&X :: operator =(const X&)[with U = int; T = double]。

因此,您正确的是,隐式生成的operator=(const X&)将由基础类型实例化,并且不会将X<int>分配给X<double> 正如Scott Meyers(请参阅上面的参考资料)所述,您的编译器面临着对X<double> b.operator=的调用,该调用采用了const X<double> ,并且发现不存在这样的函数。 因此,您的编译器然后尝试找到可接受的隐式类型转换序列,该序列可用于使调用成功, 请参阅cpp参考中的规则 您的编译器会找到通用的用户定义转换,并将X<int>转换为X<double>以具有b.operator=的正确参数类型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM