I was trying to implement a copy constructor for a class template that allows for all instantiations to converted from one version of the class template to the other.
This lead to the following code
#include <memory>
#include <iostream>
template<bool binary>
class Bar {
private:
friend class Bar<!binary>;
std::unique_ptr<int> data;
public:
Bar(int example) : data(std::make_unique<int>(example)) {
}
template<bool value>
Bar(const Bar<value>& bar) : data(std::make_unique<int>(*bar.data)) {
}
//other methods that differ depending on binary value...
};
int main() {
Bar<false> b1{ 1 };
Bar<false> b2{ b1 }; //causes compile error
Bar<true> b3{ b1 }; //works as expected
}
Constructing from a different type works but constructing from the same type issues a compile time error stating
Bar::Bar(const Bar &)': attempting to reference a deleted function
Apparently the generic copy constructor isn't being called which led to me manually writing out the copy constructor, leading to the current code.
#include <memory>
#include <iostream>
template<bool binary>
class Bar {
private:
friend class Bar<!binary>;
std::unique_ptr<int> data;
public:
Bar(int example) : data(std::make_unique<int>(example)) {
}
Bar(const Bar& bar) : data(std::make_unique<int>(*bar.data)) {
}
template<bool value>
Bar(const Bar<value>& bar) : data(std::make_unique<int>(*bar.data)) {
}
//other methods that differ depending on binary value...
};
int main() {
//all work as expected.
Bar<false> b1{ 1 };
Bar<false> b2{ b1 };
Bar<true> b3{ b1 };
Bar<true> b4{ b3 };
}
It's worth noting that this is also necessary for the move constructor, copy assignment operator, and move assignment operator. Thus, I have two questions
From https://en.cppreference.com/w/cpp/language/copy_constructor
A copy constructor of class T is a non-template constructor whose first parameter is T&, const T&, volatile T&, or const volatile T&, and either there are no other parameters, or the rest of the parameters all have default values.
Hence you can't define new parameters for the copy ctor in that way.
Now, if you use Bar<false>(const Bar<true>&)
or Bar<false>(const Bar<true>&)
, the compiler will use the ordinary cpy ctor which has been generated on instantiating the class and won't instantiate your corresponding templated ctor.
And If this is true, leave the job for the compiler to define the copy ctor but change the unique_ptr
to shared_ptr
(because with unique_ptr
as a member var the class is not copyable), or define two ctors as you have in the second code.
For the following code, I used shared_ptr
and there is no error has occurred
but notice that the templated cpy ctor doesn't execute for Bar<false/true>(const Bar<false/true>&)
while it executes for Bar<true/false>(const Bar<false/false>&)
#include <memory>
#include <iostream>
template<bool binary>
class Bar {
private:
Bar& operator=(const Bar&) = delete ;
friend class Bar<!binary>;
std::shared_ptr<int> data;
public:
template<bool value>
Bar(const Bar<value>& bar) : data(std::make_shared<int>(*bar.data)) {
std::cout << __PRETTY_FUNCTION__ <<"\n";
}
Bar(int example) : data(std::make_shared<int>(example)) {
}
//other methods that differ depending on binary value...
};
int main() {
Bar<false> b1{ 1 };
Bar<false> b2{ b1 };
Bar<true> b3 {b1};
Bar<true> b4 {b3};
Bar<false> b5 {b4};
}