如何防止函数模板中的隐式转换?

How can I prevent implicit conversions in a function template?

本文关键字:转换 何防止 函数模板      更新时间:2023-10-16

如何定义函数模板以防止隐式转换?

似乎我可以防止使用非模板函数但不使用函数模板的隐式转换。

将转发引用函数模板定义为= delete过于激进,因为它会阻止使用非 const 左值引用进行调用。

将具有常量右值参数的函数模板定义为=delete[1] 不会阻止隐式转换。

为特定类型定义 rvalue 重载=delete有效,但我想用模板完成此操作。

最小代码示例:

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
}

我的实际用例是变体的哈希,如果哈希函数不是专门针对所有变体成分,则将变体子类型隐式转换回类似变体的类型将导致无限递归。不过,上面的示例代码更清晰。

[1] 在为什么我可以阻止基元而不是用户定义类型的隐式转换中尝试,但有一个损坏的代码示例。

以下重载将阻止隐式转换:

template <class T>
void no_conversions(T) = delete; // 7
void no_conversions(const B&) {} // 8

并导致:

// Requested behaviour.
no_conversions(a); // resolves to 7
no_conversions(b); // resolves to 8

值重载会毒害隐式转换的重载集,因为它将是完全匹配的。

编辑:

template <class T>
void no_conversions(const T&) = delete; // 9
void no_conversions(const B&) {}        // 10

效果也一样。