Template error when returning value

Asked

Viewed 116 times

2

I am implementing a class that represents an array using template and dynamic allocation. However, when the +(addition) operator was overloaded, the following build error occurred (only when I try to add the objects the error occurs).

inserir a descrição da imagem aqui

template<typename T>
Matriz<T> Matriz<T>::operator+(const Matriz<T> & sum)
{
     if(linha != sum.linha || coluna != sum.coluna)
    {
       throw std::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;
   }
}

One case where the error occurs is the following code:

Matriz<int> matriz1;
Matriz<int> matriz2;
matriz1 + matriz2;
  • 1

    You came to implement the copy builder?

  • Yes, I implemented the copy builder. Could it be causing the error somehow ? I’m trying to solve this ten yesterday, but I’m not having much success =/. I will edit the question and I will put everything you are implementing in the class. I have tested the methods and found not even a problem.

  • 1

    I imagine so, given that the mistake seems to happen just in him ("in matching" seems to indicate that it has not found the appropriate copy builder).

  • 1

    (educated Guess here): you tried taking out the explicit copy builder? Maybe the difficulty is there. More info here and here

  • 1

    You’re right. I removed Explicit and it’s code worked. Thank you very much for the help, I guess I would never think that the problem could be Explicit. I didn’t even remember that he was there to tell the truth. Thank you very much.

  • Good that it was this. : ) I put as an answer then.

Show 1 more comment

1 answer

3


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

This clause exists to prevent the compiler from making conversions (casting) implicit that, although they may be useful many times, they are sometimes undesirable. Consider this example (taken from this issue in 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);
}

As the class Foo, expected in the method call DoBar, has a constructor that expects an integer, the compiler is able to convert the value 42 implicitly for an instanic of the class Foo calling this builder. If you use the clause explicit in the constructor, this behavior will be prevented during the build, and the only possible way will be to actually pass an explicit reference to the class: DoBar(Foo(42)).

In your case, the sum operator implementation returns a copy of an internal instance of the class in return temp;, that therefore it is not a direct initialization. Since your copy constructor has been declared explicit, the compiler treats this as an error because it does not allow the implicit conversion of a Matriz<int> (the variable temp) for a const Matriz<int> & (what is expected by the only available copy builder). Therefore, the simplest solution is to remove the clause explicit of the manufacturer’s declaration.

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

Browser other questions tagged

You are not signed in. Login or sign up in order to post.