Template error returning value

2

I'm implementing a class that represents an array using template and dynamic allocation. However, when I did overload the + operator (addition) the following compilation error occurred (only when I try to add the objects does the error occur).

template<typenameT>Matriz<T>Matriz<T>::operator+(constMatriz<T>&sum){if(linha!=sum.linha||coluna!=sum.coluna){throwstd::domain_error("The number of rows and columns must be equal");
    }
    else
    {
       Matriz<T> temp(linha, coluna);
       for(size_t i = 0; i < linha ; i++)   
       {
           for(size_t j = 0; j < coluna; j++)   
           {
              temp[i][j] = ptr[i][j] + sum[i][j];
           }
       }
     return temp;
     }
}

Matrix.h

template<typename T>
class Matriz
{
    //sobrecarga dos operadores padrão de entrada e saida
    friend std::ostream &operator<< <T>(std::ostream &, const Matriz<T> &);
    friend std::istream &operator>> <T>(std::istream &, Matriz<T> &);

public:
    //construtor. Pode atirar a exceção bad_alloc. 
    explicit Matriz(const size_t = 0, const size_t = 0);
    //destruidor
    virtual ~Matriz();
    //construtor da copia. Pode atirar a exceção bad_alloc  
    explicit Matriz(const Matriz<T> &);
    //Move constructor
    explicit Matriz(Matriz<T> &&);

    T & at(const size_t, const size_t);
    T at(const size_t, const size_t) const;

    T* operator[](const size_t);
    const T * const operator[](const size_t ) const;

    Matriz<T> operator+(const Matriz<T> &);
    //sobrecarga do operador de atribuição. Pode atirar a exceção bad_alloc
    const Matriz<T> &operator=(const Matriz<T> &);
    const Matriz<T> &operator=(Matriz<T> &&);
    //retorna true somente se todos os elementos das matrizes
    //forem iguais. Se não retorna false.
     bool operator==(const Matriz<T> &) const;
     //retorna true se as matriz forem iguais se não retorna false
     bool operator!=(const Matriz<T> &a) const
     {
         return !(*this == a);  
     }

private:
     T ** ptr;
     size_t linha;
     size_t coluna;
};

Copy Builder:

 template<typename T>
 Matriz<T>::Matriz(const Matriz<T> &a)
    :linha(a.linha), coluna(a.coluna)   
 {
    if(a.ptr != nullptr)
    {
        ptr = new T *[linha];
        size_t i;
        try // aloca espaço para a matriz
        {
            for(i = 0; i < coluna ; i++)    
            {
                ptr[i] = new T[coluna];
            }
        }
        catch(...)  // caso não acha espaço
        {
            for(size_t j = 0; j < i ; j++)
                delete [] ptr;
            throw std::bad_alloc();
        }

        for(size_t i = 0; i < linha ; i++) // copia os elementos
        {
             for(size_t j = 0; j < coluna; j++) 
             {
                   ptr[i][j] = a.ptr[i][j];     
             }
        }
    }//fim do if
    else
    {
       linha = 0;
       coluna = 0;
       ptr = nullptr;
   }
}

A case where the error occurs is the following code:

Matriz<int> matriz1;
Matriz<int> matriz2;
matriz1 + matriz2;
    
asked by anonymous 07.05.2015 / 21:20

1 answer

3

The problem is the use of explicit in the copy constructor definition.

This clause exists to prevent the compiler from performing implicit casting conversions which, while often useful, are sometimes undesirable. Consider this example ( removed from SOEN ):

class Foo
{
    public:
      // construtor com um único parâmetro, pode ser usado em conversão implícita
      Foo (int foo) : m_foo(foo) 
      {
      }

      int GetFoo() { return m_foo; }

    private:
      int m_foo;
};

void DoBar (Foo foo)
{
    int i = foo.GetFoo();
}

int main ()
{
    DoBar(42);
}

Because the Foo class, expected in the DoBar method call, has a constructor that expects an integer, the compiler is able to do the 42 implicitly for an instance of class Foo by calling this constructor. If you use the explicit clause in the constructor, this behavior will be prevented during compilation, and the only possible way is actually passing an explicit reference to the class: DoBar(Foo(42)) .

In your case, the implementation of the sum operator returns a copy of an internal instance of the class in return temp; , which is therefore not a direct initialization. Because your copy constructor was declared explicit, the compiler treats this as an error because it does not allow the implicit conversion of a Matriz<int> (the variable temp ) to a const Matriz<int> & (which is expected by the single constructor of copy available). So the simplest solution is to remove the explicit clause from the constructor declaration.

More details of the justification for this behavior can be found in this SOEN response .

    
08.05.2015 / 16:12