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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/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_Gcc_Static Cast - Fatal编程技术网

C++ 模板赋值算子问题

C++ 模板赋值算子问题,c++,templates,gcc,static-cast,C++,Templates,Gcc,Static Cast,我想确定这件事&赋值运算符中的rhs。但它不会编译。有什么建议吗 template <typename T> class A { public: A() { std::cout << "Default Constructor" << std::endl; } A(const T& t) : m_t(t) { std::cout << "Templated Co

我想确定这件事&赋值运算符中的rhs。但它不会编译。有什么建议吗

template <typename T>
class A {
  public:
      A() {
          std::cout << "Default Constructor" << std::endl;
      }

      A(const T& t) : m_t(t) {
          std::cout << "Templated Constructor" << std::endl;
      }

      template <typename X>
      A( const A<X>& rhs ) : m_t( (static_cast< A<T> >(rhs)).m_t ) {
            std::cout << "Copy Constructor" << std::endl;
      }

      template <typename X>
      const A& operator=( A<X>& rhs) {
            std::cout << "Assignment Operator" << std::endl;
            if (this != static_cast< A<T>* > (&rhs) )
                m_t = rhs.get();
            return *this;
      }

      T get() { return m_t; }
  private:
      T m_t;
};


class base {};
class derived : public base {};


int main()
{
    A<base*> test1;
    A<derived*> test2;
    test1 = test2;  
}
模板
甲级{
公众:
(){

std::cout你在这里想做什么

if (this != static_cast< A<T>* > (&rhs) )
关于目前正在发生的事情的要点:

  • 我没有任何复制构造函数。在现实生活中,我们会将赋值逻辑移到复制构造函数中,并使用实现赋值运算符。暂时保持代码简短(er)
  • 赋值运算符实际上什么都不做,但它们将编译
    iff
    它们的“正常”,执行您应该执行的操作
  • 有两个分配运算符:第一个用于将
    Aggregate
    分配给
    Aggregate
    ,第二个用于将
    Aggregate
    分配给
    Aggregate
    。这是Tony的答案,是“正确的方法”
  • 免费的
    运算符==
    用于为未隐式定义的类型伪造比较运算符。具体而言,我们需要为包含
    聚合的代码在
    U
    不是基元类型时进行编译
  • 运动守则 这里是所有乐趣所在:

    int main(int argc, char* argv[])
    {
        base b;
        derived d;
        unrelated u;
    
        Aggregator<base*> aggPB(&b);
        Aggregator<base*> aggPBDerivedInstance(&d);
        Aggregator<derived*> aggPD(&d);
        Aggregator<unrelated*> aggPU(&u);
    
        Aggregator<base> aggB(b);
        Aggregator<base> aggBDerivedInstance(d); // slicing occurs here
        Aggregator<derived> aggD(d);
        Aggregator<unrelated> aggU(u);
    
        std::cout << "1:" << std::endl;
    
        // base* = base*; should compile, but SKIP assignment
        // Reason: aggregate values are the same pointer
        aggPB = aggPB;
    
        // base = base; should compile, perform assignment
        // Reason: aggregate values are different copies of same object
        aggB = aggB;
    
        std::cout << "2:" << std::endl;
    
        // base* = base*; should compile, perform assignment
        // Reason: aggregate values are pointers to different objects
        aggPB = aggPBDerivedInstance;
    
        // base = base; should compile, perform assignment
        // Reason: aggregate values are (copies of) different objects
        aggB = aggBDerivedInstance;
    
        std::cout << "3:" << std::endl;
    
        // base* = derived*; should compile, perform assignment
        // Reason: aggregate values are pointers to different objects
        aggPB = aggPD;
    
        // base = derived; should compile, perform assignment (SLICING!)
        // Reason: derived is implicitly convertible to base, aggregates are (copies of) different objects
        aggB = aggD;
    
        std::cout << "4:" << std::endl;
    
        // base* = derived*; should compile, but SKIP assignment
        // Reason: aggregate values are (differently typed) pointers to same object
        aggPBDerivedInstance = aggPD;
    
        // base = derived; should compile, perform assignment (SLICING!)
        // Reason: derived is implicitly convertible to base, aggregates are (copies of) different objects
        aggBDerivedInstance = aggD;
    
        std::cout << "5:" << std::endl;
    
        // derived* = base*; should NOT compile
        // Reason: base* not implicitly convertible to derived*
        // aggPD = aggPB;
    
        // derived = base; should NOT compile
        // Reason: base not implicitly convertible to derived
        // aggD = aggB;
    
        return 0;
    }
    
    那么…我们从中学到了什么

  • 模板化赋值运算符(如编写的)将不会编译,除非聚合的类型之间存在隐式转换。这是一件好事。此代码将无法编译,而不会崩溃
  • 相等性测试只为我们节省了两个赋值,它们都是指针赋值(非常便宜,我们不需要检查)
  • 我认为这意味着平等检查是多余的,应该取消

    但是,如果:

  • T1
    T2
    是相同的类型,或者存在隐式转换,并且
  • T1
    的赋值运算符或
    T2
    的转换运算符非常昂贵(这会立即消除原语),并且
  • 一个
    bool操作符==(常数T1&lhs,常数T2&rhs)
    比上述赋值/转换操作符的运行时开销小得多
  • 然后检查是否相等可能有意义(取决于您希望
    运算符==
    返回
    true
    的频率)

    结论 如果您打算将聚合器
    仅用于指针类型(或任何其他原语),则等式测试是多余的

    如果你打算用它来构造昂贵的类类型,那么你需要一个有意义的相等运算符来配合它们。如果你也用它来构造不同的类型,那么也需要转换运算符。

    如果这真的让你感到困扰,你可以用第二个不需要强制转换的非模板化
    运算符=
    。为避免重复,如果此!=&rhs,它可以显式调用模板版本。示例说明如何调用正确的运算符:

    #include <iostream>
    
    template <class T>
    struct X
    {
        X& operator=(X& rhs)
        {
            std::cout << "non-template " << (this == &rhs ? "self\n" : "other\n");
        }
    
        template <class U>
        X& operator=(X<U>& rhs)
        {
            std::cout << "template\n";
        }
    };
    
    int main()
    {
        X<int> x;
        x = x;
        X<int> y;
        x = y;
        X<double> z;
        x = z;
    }
    
    #包括
    样板
    结构X
    {
    X和运算符=(X和rhs)
    {
    
    std::cout好的版本:实现复制赋值操作符,该操作符采用与类本身完全相同的类型:

    const A& operator=( A<T>& rhs) {
        std::cout << "copy assignment operator" << std::endl;
        if(this != &rhs)
            m_t = rhs.m_t;
        return *this;
    }
    
    编辑:实际上,第二个版本不起作用,因为使用了编译器生成的复制赋值运算符。因此,只需自己实现一个。--结束编辑

    另外,您不需要使用
    rhs.get(),只使用<代码> RS.MyT,因为您可以从类本身访问私有成员。

    < P>我个人认为以下是最优雅的解决方案。我不确定为什么我起初没有得到它。我最初是使用流血C++编译器,它似乎失败了,但是G++是最干净的?< /P> 如果有人不同意我的意见,我会删除我的答案,然后交给其他人。请注意,A*实际上意味着A*,但它是必需的

      template <typename X>
      const A& operator=( A<X>& rhs) {
            std::cout << "Assignment Operator" << std::endl;
            if (this != reinterpret_cast< A* >(&rhs))  
                m_t = rhs.get();               
            return *this;
      }
    
    模板
    常量A和运算符=(A和rhs){
    
    std::cout在您的情况下,不需要测试自赋值。与某些教程可能建议的相反,自赋值测试通常对重载赋值运算符不是必需的

    只有当(实现不好的)赋值运算符首先释放资源,然后创建新资源作为右侧运算符和资源的副本时,才需要这样做。只有这样,自赋值才会变成灾难性的,因为左侧对象会释放右侧操作数(自身)的资源同时,

    poor_assignment& operator=(const poor_assignment& rhv)
    {
        this->Release(); // == rhv.Release() in case of self-assignment
        this->Create(rhv.GetResources()); 
    }
    

    是的-我明白,我想我的问题是,检查rhs地址在“this”中是否不相同的最优雅的方法是什么。这是赋值运算符的典型方法,以确保您没有将对象赋值给自身。@stackmate:用解决方案更新。不确定“the”不过,解决办法是避免重新解释演员阵容,不过,有时候还是有必要的。@Jon:这太难看了(正如@larsmans所说)。我希望有更优雅的答案-我会等?如果没有,我想我会接受你的答案。@stackmate:我们鼓励你在接受答案前等待1-2天,特别是如果答案不完全是你想要的。@Xeo:谢谢-我会等更长时间我不确定你想要实现什么功能,但我认为你把你的答案搞糟了
    const
    在您的声明中。如果您返回一个
    const
    引用,您就失去了客户端执行操作符链接的能力。即
    (a=b)=c
    此外,我认为您不希望您的函数能够编辑输入变量?也许类似的东西看起来会更好
    a&operator=(const a&rhs)
    是的-你是对的。该常量应该被删除。是的-我想到了这一点,但在这种情况下,U是指向T的派生版本的指针,在这种情况下,我肯定要检查否?@stackmate:所以我们考虑X::operator=(X&)?这是一个合理的赋值-X和X ar
    template<class X>
    const A& operator=( A<X>& rhs) {
        std::cout << "Assignment Operator" << std::endl;
        if((intptr_t)(this) != (intptr_t)(&rhs))
            m_t = rhs.get();
        return *this;
    }
    
      template <typename X>
      const A& operator=( A<X>& rhs) {
            std::cout << "Assignment Operator" << std::endl;
            if (this != reinterpret_cast< A* >(&rhs))  
                m_t = rhs.get();               
            return *this;
      }
    
    poor_assignment& operator=(const poor_assignment& rhv)
    {
        this->Release(); // == rhv.Release() in case of self-assignment
        this->Create(rhv.GetResources()); 
    }