How can I define a function template to prevent implicit conversions?
It seems I can prevent implicit conversions using non-template functions but not using function templates.
Defining a forwarding reference function template as = delete
is too aggressive as it prevents invocation with non-const lvalue references.
Defining an function template with a const rvalue argument as =delete
[1]
does not prevent implicit conversions.
Defining an rvalue overload for a specific type as =delete
works but I'd like to accomplish this with templates.
Minimal code example:
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-world use case is hashing of variants where implicit conversion of a variant sub-type back to the variant-like type will cause infinite recursion if the hash function is not specialized for all the variant constituents. The sample code above is clearer though.
[1] Attempted in Why can I prevent implicit conversions for primitives but not user-defined types? but with a broken code example.