问题
I'm writing a class where I have a templated constructor and copy constructor. Every time I want to call copy constructor with non const object, templated constructor gets chosen. How can I force compiler to choose copy constructor?
Here is the mcve:
#include <iostream>
struct foo
{
foo()
{
std::cout << "def constructor is invoked\n";
}
foo(const foo& other)
{
std::cout << "copy constructor is invoked\n";
}
template <typename T>
foo(T&& value)
{
std::cout << "templated constructor is invoked\n";
}
};
int main()
{
foo first;
foo second(first);
}
Deleting a function is not what I want.
回答1:
The problem is that first
is mutable, so a reference to it is a foo&
which binds to the universal reference T&&
more readily than const foo&
.
Presumably, you intended that T
was any non-foo class?
In which case a little bit of enable_if
chicanery expresses intent to the compiler without having to write a load of spurious overloads.
#include <iostream>
struct foo
{
foo()
{
std::cout << "def constructor is invoked\n";
}
foo(const foo& other)
{
std::cout << "copy constructor is invoked\n";
}
template <typename T, std::enable_if_t<not std::is_base_of<foo, std::decay_t<T>>::value>* = nullptr>
foo(T&& value)
{
std::cout << "templated constructor is invoked\n";
}
};
int main()
{
foo first;
foo second(first);
foo(6);
}
expected output:
def constructor is invoked
copy constructor is invoked
templated constructor is invoked
回答2:
Add another constructor:
foo(foo& other) : foo( const_cast<const foo&>(other)) // for non-const lvalues
{
}
The first
object in your example code is a non-const lvalue, therefore the compiler prefers foo(foo&)
over foo(const &)
. The former is provided by the template (with T=foo&
) and therefore is selected.
This solution involves providing a (non-template) constructor for foo(foo&)
which then delegates construction to the copy constructor by casting it to a reference-to-const
Update, I've just realised that a foo
rvalue will be taken by the template also. There are a number of options here, but I guess the simplest is to also add a delegate for foo(foo&&)
, similar to the one above
foo(foo&& other) : foo( const_cast<const foo&>(other)) // for rvalues
{
}
来源:https://stackoverflow.com/questions/39424341/force-compiler-to-choose-copy-constructor-with-const-t-as-a-parameter