如何防止功能模板中的隐式转换?

时间:2017-05-16 08:15:41

标签: c++ templates overload-resolution

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

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

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

将const rvalue参数定义为=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]在Why can I prevent implicit conversions for primitives but not user-defined types?中尝试过,但代码示例已损坏。

1 个答案:

答案 0 :(得分:1)

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

this.quiz[4] = {
  "question-no":this.no,
  "Ans":this.ans
};

并导致:

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

同样适用。