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

C++ template: no matching function for call

我无法理解为什么这个程序无法使用 -std=c++14 使用 g++ 7.3 或 clang++ 5.0 进行编译。

A 可以从 const int 初始化,如图所示。也可以从 const int 创建对 A 的 const 引用,但使用 const int 调用 f(const A &) 失败。为什么?

#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;
}

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

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

给定 f(i);,应用 copy initialization。而i(with type const int)需要转换为A,需要两次自定义转换;从 const intV,从 VA。但是在一个隐式转换序列中只允许一个用户自定义转换。

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

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

In addition, the implicit conversion in copy-initialization must produce T directly from the initializer, while, e.g. direct-initialization expects an implicit conversion from the initializer to an argument of T's constructor.

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

这里您需要两次连续的隐式类型转换,但是 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} { }
};

复制初始化不支持两个用户定义的转换。解决这个问题的简单方法是用 A 包装 i,同时用 f(A(i))

传递给函数 f