如何防止函数模板中的隐式转换?
How can I prevent implicit conversions in a function template?
如何定义函数模板以防止隐式转换?
看来我可以使用非模板函数而不是函数模板来防止隐式转换。
将转发引用函数模板定义为 = delete
过于激进,因为它会阻止使用非常量左值引用进行调用。
定义一个带有 const 右值参数的函数模板 =delete
[1]
不会阻止隐式转换。
将特定类型的右值重载定义为 =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
同样有效。
如何定义函数模板以防止隐式转换?
看来我可以使用非模板函数而不是函数模板来防止隐式转换。
将转发引用函数模板定义为 = delete
过于激进,因为它会阻止使用非常量左值引用进行调用。
定义一个带有 const 右值参数的函数模板 =delete
[1]
不会阻止隐式转换。
将特定类型的右值重载定义为 =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
同样有效。