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 int
到 V
,从 V
到 A
。但是在一个隐式转换序列中只允许一个用户自定义转换。
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
我无法理解为什么这个程序无法使用 -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 int
到 V
,从 V
到 A
。但是在一个隐式转换序列中只允许一个用户自定义转换。
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