调用可变参数函数模板时,C ++ 11模棱两可的重载

时间:2018-09-04 10:09:30

标签: c++ variadic-templates

您能否解释为什么我使用显式模板实例化却拥有error: call of overloaded ‘func(const Test&)’ is ambiguous吗?

#include <iostream>

struct Test {
};

void func(const Test &) {
  std::cout << "By Reference" << std::endl;
}

void func(const Test) {
  std::cout << "By Value" << std::endl;
}

template <typename... TArgs>
void wrap(TArgs... args) {
  func(args...);
}

int main() {
  Test t;
  wrap<const Test &>(t);
  return 0;
};

编辑

歧义的原因是两个因素的结合。首先是在调用func(args...)中应用了简单的重载规则。第二个是简单函数不能被值和const引用重载。为确保这一点,可以将呼叫wrap<const Test &>(t)替换为func(static_cast<const Test &>(t))。错误仍然存​​在。

要解决此问题,可以将函数模板用于func,并将值vs常量引用模板特化,如@lubgr提供的示例所示

感谢大家帮助我揭开这个概念的神秘面纱。

2 个答案:

答案 0 :(得分:3)

出于相同的原因,以下调用是不明确的:

#include <iostream>
void foo(int) { std::cout << "val" << std::endl; }
void foo(const int&) { std::cout << "ref" << std::endl; }

int main()
{
  int i = 1;
  foo(i);
}

有关该案例的完整讨论,请参见here

答案 1 :(得分:2)

在显式实例化wrap函数模板的情况下,假设编译器在wrap实例化中,知道Targs...确实是const Test&。那么应该选择哪个函数重载?它不能选择一个,因为wrap的模板参数不会传播到普通(非模板)函数。相反,将应用简单的重载规则。

如果您也将func更改为功能模板,则可以看到差异并解决问题:

template <class T> void func(T);

template <> void func<const Test&>(const Test&) {
  std::cout << "By Reference" << std::endl;
}

template <> void func<const Test>(const Test) {
  std::cout << "By Value" << std::endl;
}

那么,当您明确要求时,就会调用适当的专业化。

template <typename... TArgs>
void wrap(TArgs... args) {
  func<TArgs...>(args...); // Note, the type is specified here, again.
}