模板运算符的问题=常数参数的问题 这是C++,使用Visual Studio 2019(没有尝试其他编译器)。 我想添加一个模板化操作符=方法。如果参数为非常量,则工作正常。但是如果参数是const,即使我使用const参数创建了一个版本,也不会调用它。相反,它做一个简单的浅拷贝

模板运算符的问题=常数参数的问题 这是C++,使用Visual Studio 2019(没有尝试其他编译器)。 我想添加一个模板化操作符=方法。如果参数为非常量,则工作正常。但是如果参数是const,即使我使用const参数创建了一个版本,也不会调用它。相反,它做一个简单的浅拷贝,c++,templates,constants,operator-keyword,C++,Templates,Constants,Operator Keyword,如果我使用一个命名函数而不是运算符,它将按预期工作。类似地,如果没有模板化,则按预期调用操作符。这个组合似乎是个问题 class CTest { public: int x{}; CTest() = default; CTest(int value) : x(value) {} // non-const operator= template<class SrcType>void operator=(SrcType& src)

如果我使用一个命名函数而不是运算符,它将按预期工作。类似地,如果没有模板化,则按预期调用操作符。这个组合似乎是个问题

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;
}
这里有一个例子说明了这个问题

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;
}
class-CTest
{
公众:
int x{};
CTest()=默认值;
CTest(int值):x(值){}
//非常量运算符=
templatevoid运算符=(SrcType和src)
{
x=src.x;
}
//常量运算符=
templatevoid运算符=(常量SrcType&src)
{
x=src.x;
}
};
int main()
{
CTest非STSRC{3};
const CTest constSrc{5};
测试结果;
result=nonConstSrc;//正确调用non-const运算符=
结果=constSrc;//?浅拷贝,不调用const运算符=
返回0;
}

有没有办法让它使用我的重载函数?谢谢。

您的const函数模板没有被调用,因为编译器默认生成了默认的复制赋值运算符,它具有签名
运算符=(const CTest&)
。当编译器必须在非模板函数和模板函数之间进行选择时(当两者具有相同的匹配项时),首选前者。这就是为什么不调用模板化方法的原因

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

CTest& operator=(const volatile CTest&) = delete;
如上所述,您禁用了普通运算符=,
volatile
这里很重要,没有它,编译器会抱怨
运算符=
被禁用。通过添加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");
 }
模板
void运算符=(SrcType和src)
{
x=src.x;
看跌期权(“boom1”);
}
模板
void运算符=(常量SrcType&src){
x=src.x;
看跌期权(“boom2”);
}

如果类没有声明副本赋值,编译器将隐式生成一个副本赋值

类没有复制赋值运算符,它只有一个模板赋值运算符

当使用
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;
}
#包括
类别测试
{
公众:
int x{};
CTest()=默认值;
CTest(int值):x(值){}
CTest(const CTest&v)=删除;
CTest和操作员=(常数CTest和v){
返回运算符=(v);
}
//非常量运算符=
templateCTest和operator=(SrcType和src)
{
x=src.x;

std::cout你为什么想要一个非常量版本?你没有修改
src
,所以一个就足够了。从你的编译器的角度来看,
非stsrc
没有被赋值调用修改,因此常量版本被调用。删除
volatile
复制赋值是一种非常有趣的方法。偷偷摸摸的。:-)谢谢,ra修复,就是这样。volatile关键字是我为了避免默认副本分配而丢失的。