Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.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++_Templates_Reference_Assignment Operator - Fatal编程技术网

C++ 引用模板类型的赋值运算符需要非常量重载

C++ 引用模板类型的赋值运算符需要非常量重载,c++,templates,reference,assignment-operator,C++,Templates,Reference,Assignment Operator,我正试着把我的头脑集中在一个拷贝分配操作员的问题上。我不知道到底发生了什么,尽管我有一些想法(在最后列出)。这是一个问题,因为我使用的第三方库对其类没有控制权 假设您有一个带有复制分配运算符的模板化容器。此运算符接受另一个具有不同模板的容器,并尝试静态转换其他类型 template <class U> vec2<T>& operator=(const vec2<U>& v) { x = static_cast<T>(v.x)

我正试着把我的头脑集中在一个拷贝分配操作员的问题上。我不知道到底发生了什么,尽管我有一些想法(在最后列出)。这是一个问题,因为我使用的第三方库对其类没有控制权

假设您有一个带有复制分配运算符的模板化容器。此运算符接受另一个具有不同模板的容器,并尝试静态转换其他类型

template <class U>
vec2<T>& operator=(const vec2<U>& v) {
    x = static_cast<T>(v.x);
    y = static_cast<T>(v.y);
    return *this;
}
模板
vec2&运算符=(常量vec2&v){
x=静态_铸件(v.x);
y=静态铸件(v.y);
归还*这个;
}
这对于简单赋值很好,但是当使用对T的引用时,您会得到一个关于常量值类型的编译错误。如果添加另一个接受非常量引用的重载,它将编译并工作

我举了一个简单的例子来说明这个问题

template <class T>
struct vec2 final {
    vec2(T x_, T y_)
            : x(x_)
            , y(y_) {
    }

    template <class U>
    vec2(const vec2<U>& v)
            : x(static_cast<T>(v.x))
            , y(static_cast<T>(v.y)) {
    }

    template <class U>
    vec2<T>& operator=(const vec2<U>& v) {
        if (this == &v)
            return *this;

        x = static_cast<T>(v.x);
        y = static_cast<T>(v.y);
        return *this;
    }

    // Fix :
    /*
    template <class U>
    vec2<T>& operator=(vec2<U>& v) {
        x = static_cast<T>(v.x);
        y = static_cast<T>(v.y);
        return *this;
    }
    */

    T x;
    T y;
};
模板
结构vec2最终版本{
vec2(tx_uu,tyuu)
:x(x_)
,y(y_){
}
样板
vec2(常数vec2&v)
:x(静态投影(v.x))
,y(静态铸造(v.y)){
}
样板
vec2&运算符=(常量vec2&v){
如果(此==&v)
归还*这个;
x=静态_铸件(v.x);
y=静态铸件(v.y);
归还*这个;
}
//修正:
/*
样板
vec2&运算符=(vec2&v){
x=静态_铸件(v.x);
y=静态铸件(v.y);
归还*这个;
}
*/
tx;
T y;
};
以及我如何使用它:

int main(int, char**) {
    vec2<int> v0 = { 0, 0 };
    vec2<int> v1 = { 1, 1 };
    vec2<int&> test[] = { { v0.x, v0.y }, { v1.x, v1.y } };

    vec2<int> muh_vec2 = { 2, 2 };
    test[0] = muh_vec2;
    printf("{ %d, %d }\n", test[0].x, test[0].y);

    return 0;
}
int main(int,char**){
vec2v0={0,0};
vec2v1={1,1};
vec2测试[]={{v0.x,v0.y},{v1.x,v1.y};
vec2 muh_vec2={2,2};
测试[0]=muh_vec2;
printf(“{%d,%d}\n”,测试[0].x,测试[0].y);
返回0;
}
最新的AppleClang将生成以下错误:

main4.cpp:18:7: error: binding value of type 'const int' to reference to type 'int'
      drops 'const' qualifier
                x = static_cast<T>(v.x);
                    ^              ~~~
main4.cpp:63:10: note: in instantiation of function template specialization 'vec2<int
      &>::operator=<int>' requested here
        test[0] = muh_vec2;
                ^
main4.cpp:18:7:错误:将“const int”类型的值绑定到对“int”类型的引用
删除“const”限定符
x=静态_铸件(v.x);
^              ~~~
main4.cpp:63:10:注意:在函数模板专门化的实例化中,此处请求了“vec2::operator=”
测试[0]=muh_vec2;
^
我从中了解到,编译器试图通过const值赋值。但是,为什么会有一个非侵入性的解决方案来解决这个问题呢

我确实在这里发现了一个类似的问题:

阅读了这个问题后,我的结论是:可能是默认赋值运算符导致了这个问题?我仍然不明白为什么:/

以下是一个在线示例:

这显然是非法的:不能将常量int静态强制转换为非常量引用

一般解决方案基本上需要重建
std::tuple
std::pair
机制。SFINAE可以用来引导它。但一般来说,包含引用的结构和包含值的结构通常是完全不同的;将一个模板同时用于两个模板是有问题的

template <class T>
struct vec2 final {
  template<class Self,
    std::enable_if_t<std::is_same<std::decay_t<Self>, vec2>>{}, bool> =true
  >
  friend auto as_tuple( Self&& self ){
    return std::forward_as_tuple( std::forward<Self>(self).x, std::forward<Self>(self).y );
  }
模板
结构vec2最终版本{
模板=真
>
朋友自动作为组(自我和自我){
将std::forward作为(std::forward(self).x,std::forward(self).y)元组返回;
}
然后我们可以进行SFINAE测试来确定
as_tuple(LHS)=as_tuple(RHS)
是否有效

为构造这样做是另一个痛苦,因为LHS的元组类型需要在构造性测试开始工作之前进行按摩



<> p>代码越通用,工作量就越大。在编写无限泛型代码之前考虑实际用例。

<代码> x= StasyType(V.x)可能。或者甚至可能只是
x=v.x;
并依赖隐式转换。因此,删除引用是有效的。你知道为什么吗?你知道不需要修改容器的替代方案吗?我不确定我是否理解这个问题。你是在问如何在不修改所述代码的情况下修复错误代码吗?“这是一个问题,因为我使用的第三方库对其类没有控制权。"我怀疑
vec2
根本不是设计用来与
t
的引用类型一起使用的。因此,在不修改
vec
的情况下解决问题的一种方法就是避免以这种方式使用它。好吧,如果我理解正确的话。您可以在内部使用此帮助程序来选择要调用的类型/函数?我很难看到h如何将as\U tuple应用于我的问题。@scx采用
运算符=(U&&)
并在
as\U tuple(*this)=as\U tuple(U&)时进行SFINAE测试
是有效的,并在内部将其用作您的实现。说得清楚一点,我是说这会给您带来您似乎想要的东西;我不是说这是一个好主意。哦,好吧。我正在尝试重新思考我的容器,但我真的没有看到其他方法(现在).我现在将使用std::remove_引用,因为它似乎不太涉及。谢谢您的帮助!
this->x = static_cast<int&>(v.x);
template <class T>
struct vec2 final {
  template<class Self,
    std::enable_if_t<std::is_same<std::decay_t<Self>, vec2>>{}, bool> =true
  >
  friend auto as_tuple( Self&& self ){
    return std::forward_as_tuple( std::forward<Self>(self).x, std::forward<Self>(self).y );
  }