【发布时间】:2017-05-16 08:15:41
【问题描述】:
如何定义函数模板以防止隐式转换?
看来我可以防止使用非模板函数但不使用函数模板的隐式转换。
将转发引用函数模板定义为= 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] 在 Why can I prevent implicit conversions for primitives but not user-defined types? 中尝试,但代码示例损坏。
【问题讨论】:
-
我不清楚你在问什么 - 即为什么
no_rvalue不能解决你的问题?你提到你想要一个模板,但模板参数是什么?如果您提供main()显示更多应该或不应该编译的示例,这可能会有所帮助。 -
在处理函数方面,不要让自己处理 ICS hullabaloo。你为什么不要求你的用户专门化一个 class-template 而不是重载一个 function。我认为您应该探索使用 class-template 专业化或其他一些机制。想想
std::hash是如何设计的。 -
explicit B(const A&){}?? -
@M.M. no_rvalue 具有所需的行为,但我不希望用户指定两个非模板函数。我宁愿提供一个已删除的版本,并让用户指定他们将实施的版本。
-
@Praveen 这会停止所有比我想要的更激进的隐式转换。我也可能无法更改类构造函数的显式性质(例如 std::variant)。
标签: c++ templates overload-resolution