Search code examples
c++templatesconstructorc++17pass-by-value

templates, function uses wrong constructor to copy my object


I created a class template that initializes a simple array using the parameter pack expansion and the class has a copy constructor for my function that takes an object of that class. Initialization works, but when passing an object to my function, the initialization constructor is called and not the copy constructor.

How can I make my function use the correct constructor to be able to pass an object by value?

Working with c++17.

My class looks as follows:

template<typename I, std::size_t val>
class myClass{

    public:
        std::array<I, val> data;

    template<typename ...T>
    constexpr myClass(T&& ... elem) : data{elem...}{};

    /*copy c'tr*/
    template<typename T, std::size_t value>
    constexpr myClass(myClass<T, value> mObj){
        data = mObj.data;
    }
};

struct myStruct{
    myClass<int, 5> aC{1,2,3,4,5};
};

template<typename I, std::size_t val>
constexpr auto myfunction(myClass<T, val> obj){
    int a = obj.data[0];
    return a;
}

This is my main:

int main() {
    myStruct myStructObj;
    auto myvalue = myfunction(myStructObj.aC);
    return 0;
} 

At the end, my error message:

tensor.h: In instantiation of ‘constexpr myClass<I, val>::myClass(T&& ...) [with T = {myClass<int, 5>&}; I = int; long unsigned int val = 5]’:
main.cpp:72:30:   required from here
tensor.h:188:51: error: cannot convert ‘myClass<int, 5>’ to ‘int’ in initialization
  188 |     constexpr myClass(T&& ... elem) : data{elem...}{};
      |   

                                            ^  

Solution

  • /*copy c'tr*/

    That is not a correct assertion. This is a constructor template. A copy c'tor is always a normal member of an instantiation, never a template member function. Also, this c'tor is taking its argument by value. This is a no-starter, since function arguments that are passed by value are copy-initialized, which requires... a copy/move c'tor. The correct signature for the copy c'tor would be this

    constexpr myClass(myClass const& mObj){
        data = mObj.data;
    }
    

    Take the argument by reference (to const). A copy c'tor may exist next to your c'tor template. So you may have conversions from other instantiations and copying, both well defined.

    Or, since you are after the default implementation anyway

    constexpr myClass(myClass const& mObj) = default;