带有模板运算符的问题=带有常量参数

问题描述 投票:0回答:2

这是使用Visual Studio 2019的c ++语言(尚未尝试其他编译器)。我想添加一个模板化的operator =方法。如果参数为非常量,则可以正常工作。但是,如果参数是const,即使我使用const参数创建版本,也不会调用它。相反,它会进行简单的浅表复制。

如果我使用命名函数而不是运算符,它将按预期工作。同样,如果未使用模板,则按预期方式调用运算符。组合似乎是问题所在。

这里是一个展示问题的例子。

class CTest
{
public:
    int x{};

    CTest() = default;
    CTest(int value) : x(value) {}

    // non-const operator=
    template<class SrcType>void operator=(SrcType& src)
    {
        x = src.x;
    }

    // const operator=
    template<class SrcType>void operator=(const SrcType& src)
    {
        x = src.x;
    }
};

int main()
{
    CTest   nonConstSrc{ 3 };
    const CTest constSrc{ 5 };
    CTest result;
    result = nonConstSrc;   // correctly calls non-const operator=
    result = constSrc;      // ? shallow copy, not calling const operator=

    return 0;
}

关于如何使用重载函数的任何想法?谢谢。

c++ templates const operator-keyword
2个回答
0
投票

您的const函数模板没有被调用,因为默认情况下编译器生成了默认副本分配运算符,其签名为operator=(const CTest&)。当编译器必须在非模板函数和模板函数之间进行选择时,首选前者。这就是为什么不调用您的模板化方法的原因。

为了帮助编译器选择所需的版本,请添加:

CTest& operator=(const volatile CTest&) = delete;

在上面,您禁用了normal运算符=,volatile在这里很重要,没有它,编译器将抱怨operator=被禁用。通过添加volatile,您只需使模板版本比volatile一个更好。

其余部分不变:

 template<class SrcType> 
 void operator=(SrcType& src)
 {
     x = src.x;
     puts("boom1");
 }

 template<class SrcType>
 void operator=(const SrcType& src) {
     x = src.x;
     puts("boom2");
 }

Demo


0
投票

如果一个类没有声明副本分配,则编译器将隐式生成一个副本。

您的班级没有复制分配运算符,它只有模板分配运算符。

当用const对象调用时,隐式声明的赋值运算符在重载解决方案中是更好的匹配。

这里的问题是我们不能删除隐式声明的赋值运算符,因为它会生成编译器错误。但是,我们可以编写自己的赋值运算符以转发到模板。

#include <iostream>

class CTest
{
public:
    int x{};

    CTest() = default;
    CTest(int value) : x(value) {}


    CTest(const CTest& v) = delete;
    CTest& operator=(const CTest& v) {
        return operator=<CTest>(v);
    }

    // non-const operator=
    template<class SrcType>CTest& operator=(SrcType& src)
    {
        x = src.x;
        std::cout << "non-const\n";
        return *this;
    }

    template<class SrcType>CTest& operator=(const SrcType& src)
    {
        x = src.x;
        std::cout << "const\n";
        return *this;
    }
};

int main()
{
    CTest   nonConstSrc{ 3 };
    const CTest constSrc{ 5 };
    CTest result;
    result = nonConstSrc;   // correctly calls non-const operator=
    result = constSrc;      // calls copy-assignment and forwards to template

    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.