模板参数推断失败
Template parameter inference fails
考虑以下代码:
template<class T>
vector<T> filter(typename vector<T>::iterator begin,
typename vector<T>::iterator end,
bool (*cond)(T a))
{
vector<T> vec;
for (typename vector<T>::iterator it = begin; it != end; it++) {
if (cond(*it)) {
vec.push_back(*it);
}
}
return vec;
}
vector<int> vec = { 1,2,3,4,5,6,7,8,9,10 };
auto another_vec = filter<int>(vec.begin(), vec.end(), [](int a) {return a > 5; });
当我从函数过滤器的调用中删除类型时,代码无法编译,即写
时
filter(vec.begin(), vec.end(), [](int a) {return a > 5; });
我的问题是,为什么?编译器可以从 lambda 和迭代器中推导出类型。
我得到的错误是:
Error C2784 'std::vector>
filter(vector>::iterator,vector>::iterator,bool
(__cdecl *)(T))': could not deduce template argument for 'bool
(__cdecl *)(T)' from
'main::' example c:\users\danii\documents\visual
studio 2017\projects\example\example\source.cpp 24
我找不到有关此问题的详细信息。
我的猜测是,编译器无法推断出内部类型? (例如不能从 vector 推导出 int)。如果是这样,为什么会这样?如果不是,情况如何?有什么办法可以解决吗?
我遇到的另一件事是使用迭代器本身作为模板,即类似于
template <class T, class iter, class cond>
vector<T> filter(iter begin, iter end, cond c)
编程正确吗?我觉得这段代码有点可疑。
My guess is, the compiler can't deduce inner types? (e.g can't deduce int from vector).
是的。这属于 non-deduced contexts:
In the following cases, the types, templates, and non-type values that
are used to compose P do not participate in template argument
deduction, but instead use the template arguments that were either
deduced elsewhere or explicitly specified. If a template parameter is
used only in non-deduced contexts and is not explicitly specified,
template argument deduction fails.
1) The nested-name-specifier (everything to the left of the scope
resolution operator ::) of a type that was specified using a
qualified-id:
请注意,没有捕获的 lambda 表达式(第 3 个参数)可以隐式转换为函数指针,但 template argument deduction 不考虑隐式转换。
Type deduction does not consider implicit conversions (other than type
adjustments listed above): that's the job for overload resolution,
which happens later.
那么这里类型推导失败
您的修复想法是个好主意,但您不需要模板参数 T
,它不能(也不需要)推导出来。您可以将其更改为:
template<class iter, class cond>
auto filter(iter begin, iter end, cond c)
{
vector<typename std::iterator_traits<iter>::value_type> vec;
for (auto it = begin; it != end; it++) {
if (cond(*it)) {
vec.push_back(*it);
}
}
return vec;
}
这是因为 lambda 类型不完全是预期的函数类型,所以模板推导将不起作用。编译器不能同时进行隐式转换和模板推导。如果你使用一个函数,它会:
bool f(int a) {
return a > 5;
}
int main() {
vector<int> vec = { 1,2,3,4,5,6,7,8,9,10 };
auto another_vec = filter(vec.begin(), vec.end(), f);
return 0;
}
考虑以下代码:
template<class T>
vector<T> filter(typename vector<T>::iterator begin,
typename vector<T>::iterator end,
bool (*cond)(T a))
{
vector<T> vec;
for (typename vector<T>::iterator it = begin; it != end; it++) {
if (cond(*it)) {
vec.push_back(*it);
}
}
return vec;
}
vector<int> vec = { 1,2,3,4,5,6,7,8,9,10 };
auto another_vec = filter<int>(vec.begin(), vec.end(), [](int a) {return a > 5; });
当我从函数过滤器的调用中删除类型时,代码无法编译,即写
时filter(vec.begin(), vec.end(), [](int a) {return a > 5; });
我的问题是,为什么?编译器可以从 lambda 和迭代器中推导出类型。
我得到的错误是:
Error C2784 'std::vector> filter(vector>::iterator,vector>::iterator,bool (__cdecl *)(T))': could not deduce template argument for 'bool (__cdecl *)(T)' from 'main::' example c:\users\danii\documents\visual studio 2017\projects\example\example\source.cpp 24
我找不到有关此问题的详细信息。 我的猜测是,编译器无法推断出内部类型? (例如不能从 vector 推导出 int)。如果是这样,为什么会这样?如果不是,情况如何?有什么办法可以解决吗?
我遇到的另一件事是使用迭代器本身作为模板,即类似于
template <class T, class iter, class cond>
vector<T> filter(iter begin, iter end, cond c)
编程正确吗?我觉得这段代码有点可疑。
My guess is, the compiler can't deduce inner types? (e.g can't deduce int from vector).
是的。这属于 non-deduced contexts:
In the following cases, the types, templates, and non-type values that are used to compose P do not participate in template argument deduction, but instead use the template arguments that were either deduced elsewhere or explicitly specified. If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.
1) The nested-name-specifier (everything to the left of the scope resolution operator ::) of a type that was specified using a qualified-id:
请注意,没有捕获的 lambda 表达式(第 3 个参数)可以隐式转换为函数指针,但 template argument deduction 不考虑隐式转换。
Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.
那么这里类型推导失败
您的修复想法是个好主意,但您不需要模板参数 T
,它不能(也不需要)推导出来。您可以将其更改为:
template<class iter, class cond>
auto filter(iter begin, iter end, cond c)
{
vector<typename std::iterator_traits<iter>::value_type> vec;
for (auto it = begin; it != end; it++) {
if (cond(*it)) {
vec.push_back(*it);
}
}
return vec;
}
这是因为 lambda 类型不完全是预期的函数类型,所以模板推导将不起作用。编译器不能同时进行隐式转换和模板推导。如果你使用一个函数,它会:
bool f(int a) {
return a > 5;
}
int main() {
vector<int> vec = { 1,2,3,4,5,6,7,8,9,10 };
auto another_vec = filter(vec.begin(), vec.end(), f);
return 0;
}