C ++模板:没有匹配的调用函数

时间:2018-06-27 05:43:30

标签: c++ templates initialization implicit-conversion

我不明白为什么该程序无法使用-std = c ++ 14在g ++ 7.3或clang ++ 5.0中编译。

如图所示,可以从A初始化

const int。也可以从A创建对const int的const引用,但是用f(const A &)const int的调用失败。为什么?

#include <iostream>

struct V {
  int i;
  template <class T>
  V(const T &t) : i{t} {}
};

struct A {
  int i;
  A(V v) : i{v.i} {}
};

void f(const A &) {}

int main() {
  const auto i = 42;
  const A a1{i};              // OK
  std::cout << a1.i << '\n';  // 42
  const A &a2 = A{i};         // OK
  std::cout << a2.i << '\n';  // 42
  f(i);                       // no matching function for call to 'f'
  return 0;
}

4 个答案:

答案 0 :(得分:0)

出于函数调用的目的,将i转换为A将需要两次用户定义的转换(int -> V -> A)。该标准对每个隐式转换序列都设置了单个用户定义转换的硬性限制。

如果您尝试将a2直接绑定到i,也会发生同样的情况。因此,在为A{i}提供参数时,也需要进行功能样式转换(f

答案 1 :(得分:0)

应用f(i);copy initialization。并且i(类型为const int)需要转换为A,需要两个用户定义的转换;从const intV,以及从VA。但是在一个隐式转换序列中仅允许一个用户定义的转换。

Bot const A a1{i};const A &a2 = A{i};direct initialization,只有一个从i(类型为const int)到参数A的隐式转换的构造函数(即V)是必需的,因此它们可以正常工作。

请注意复制初始化和直接初始化之间的区别,

  

此外,复制初始化中的隐式转换必须直接从初始值设定项产生T,而例如直接初始化需要从初始值设定项到T的构造函数的参数的隐式转换。

作为解决方法,您可以先将i进行显式转换,然后再将其传递给f()

答案 2 :(得分:0)

这里需要两个连续的隐式类型转换,但是C ++可以为您做一次转换隐式转换。如果要让编译器为您生成正确的类型化代码,请对函数template使用f,如下所示。

template <typename T>
void f(const T & x) { std::cout << x << std::endl;}

之所以需要两种类型转换,是因为只有一个构造函数在结构中采用类型V。如果要摆脱两种类型的转换作为第二种解决方案,则可以添加另一个将int作为参数的构造函数,如下所示:

struct A {
    int i;
    A(V v) : i{v.i} {}
    A(int theI) : i{theI} { }
};

答案 3 :(得分:0)

副本初始化不支持两个用户定义的转换。解决该问题的简单方法是在将f传递给功能f(A(i))的同时用A包裹i