0

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...}{};
      |   

                                            ^  
M.Mac
  • 699
  • 3
  • 14
  • 2
    What if you change the signature of your copy constructor to `template constexpr myClass(const myClass &mObj)`? Wait. The declaration of copy c'tor is wrong. It must be `constexpr myClass(const myClass &mObj)` without the repeated `template typename T, std::size_t value>` before. – Scheff's Cat Feb 16 '20 at 09:42
  • 1
    Unrelated to your question, you're passing `obj` to `myfunction` as a value, instead of as a const reference. I guess in a sense it is related to the question, because for the exact same reason your compilation is failing (see @Scheff's answer). – AVH Feb 16 '20 at 09:45
  • 1
    FYI: [SO: Copy constructor of template class](https://stackoverflow.com/a/19167355/7478597) – Scheff's Cat Feb 16 '20 at 09:46

1 Answers1

3

/*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;
StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • First of all, thank you a lot! I see my error, especially that I didn't know the standard syntax for a copy c'tor. I had a problem with the c'tor you provided, but I removed the `const` and now it compiles. I read that without the `const` it becomes a move-c'tor? Is that correct?____I added this one to my code: `constexpr myClass(myClass &mObj) = default;` – M.Mac Feb 16 '20 at 09:57
  • @M.Mac - A move c'tor must take by a different reference type (`myClass&&`). What you defined is still a copy c'tor. You can actually have both defaulted versions of the copy c'tor in your code, with and without the const qualifier. Sometimes it's needed to deal with dark corners of the language. – StoryTeller - Unslander Monica Feb 16 '20 at 10:54
  • The power behind C++ is sometimes more frustrating than beneficial. haha :) – M.Mac Feb 17 '20 at 08:42