How can I prevent implicit conversions in the function template?
How can I define a function template to prevent implicit conversions?
I seem to be able to prevent implicit conversions by using non-templated functions, but not using function templates.
Defining a forwarding reference function template as = delete
being too aggressive because it prevents invocation with non-const lvalue references.
Defining a function template with a const rvalue argument as =delete
[1] does not prevent implicit conversions.
Defining an rvalue overload for a specific type is how it =delete
works, but I would like to do it with templates.
Example of minimal code:
struct A {};
struct B {
B() = default;
B(const A&) {}
};
// Delete const rvalue reference.
template <class T>
void t_no_rvalue(const T&&) = delete; // 1
void t_no_rvalue(const B&) {} // 2
// Delete forwarding reference.
template <class T>
void t_no_fwd_ref(T&&) = delete; // 3
void t_no_fwd_ref(const B&) {} // 4
// (non-template) Delete const rvalue reference.
void no_rvalue(const B&&) = delete; // 5
void no_rvalue(const B&) {} // 6
int main(int argc, char* argv[]) {
A a;
B b;
// Undesired behaviour, implicit conversion allowed.
t_no_rvalue(a); // resolves to 2
t_no_rvalue(b); // resolves to 2
// Undesired behaviour, invocation with non-const reference disallowed.
t_no_fwd_ref(a); // resolves to 3
t_no_fwd_ref(b); // resolves to 3
// Desired behaviour.
no_rvalue(a); // resolves to 5
no_rvalue(b); // resolves to 6
}
My real use case is variant hashing, where implicitly converting a variant subtype back to a variant-like type will cause infinite recursion unless the hash function is specialized for all the constituents of the variant. However, the code example is clearer.
[1] Attempt at Why can I prevent implicit conversions for primitives but not user-defined types? but with broken code example.
source to share
The following overload will prevent implicit conversions:
template <class T>
void no_conversions(T) = delete; // 7
void no_conversions(const B&) {} // 8
and results in:
// Requested behaviour.
no_conversions(a); // resolves to 7
no_conversions(b); // resolves to 8
Value overloading poisons a set of implicit conversion overloads, since it will be an exact match.
Edit:
template <class T>
void no_conversions(const T&) = delete; // 9
void no_conversions(const B&) {} // 10
works just as well.
source to share