我正在尝试创建带有可选参数的模板化函数,并且在理解为什么编译失败时遇到了麻烦。这是我的测试(人为)代码:
#include <iostream>
#include <vector>
template <class UnaryPredicate>
int GetCountIf(std::vector<int> v, UnaryPredicate pred = [](auto) { return true; }) {
int count=0;
for (auto i: v) {
if (pred(i)) {
count++;
}
}
return count;
}
int main() {
auto v = std::vector<int>{0, 1, 2, 3, 4, 5};
std::cout << "NumOddElements=" << GetCountIf(v, [](auto val) { return (val % 2 == 1); }) << '\n';
// std::cout << "NumElements=" << GetCountIf(v) << '\n';
}
仅当我同时使用两个参数调用GetCountIf()
时,代码才会编译。如果我尝试仅传递1个参数,则编译将失败,并显示以下错误:
main.cpp:18:34:错误:没有匹配的函数来调用'GetCountIf'
std :: cout <<“ NumElements =” << GetCountIf(v)<<'\ n'; ^ ~~~~~~~~~ main.cpp:5:5:注意:候选模板被忽略:无法推断模板参数 'UnaryPredicate'int GetCountIf(std :: vector v,UnaryPredicate pred = {返回true; }){ 产生了^ 1个错误。
当编译器遇到仅具有1个参数的对GetCountIf
的调用时,为什么不能推断出可选的lambda的类型?如果我像这样明确地指定谓词的类型,则它可以工作:
template <typename T, class UnaryPredicate = std::function<bool(T)>>
int GetCountIf(std::vector<T> v, UnaryPredicate pred = [](T) { return true;}) {
...
}
为什么这样做?
(我正在使用C ++ 14)
答案 0 :(得分:7)
请注意,函数参数的默认值不会用于模板参数的模板参数推导;导致模板参数推导失败,无法推导UnaryPredicate
的类型。
在以下情况下,用于构成P的类型,模板和非类型值不参与模板自变量的推导,而是使用在其他地方推导或明确指定的模板自变量。如果仅在非推导上下文中使用模板参数且未明确指定模板参数,则模板参数推导将失败。
4)在函数的参数类型中使用的模板参数 具有调用中使用的默认参数的参数 为此进行推论的
template<typename T, typename F> void f(const std::vector<T>& v, const F& comp = std::less<T>()); std::vector<std::string> v(3); f(v); // P1 = const std::vector<T>&, A1 = std::vector<std::string> lvalue // P1/A1 deduced T = std::string // P2 = const F&, A2 = std::less<std::string> rvalue // P2 is non-deduced context for F (template parameter) used in the // parameter type (const F&) of the function parameter comp, // that has a default argument that is being used in the call f(v)
和
无法从函数的类型推导类型模板参数 默认参数:
template<typename T> void f(T = 5, T = 7); void g() { f(1); // OK: calls f<int>(1, 7) f(); // error: cannot deduce T f<int>(); // OK: calls f<int>(5, 7) }
另一方面,如果您为模板参数std::function<bool(T)>
指定了默认值UnaryPredicate
,那么如果{{1 }}没有明确指定或推论。
答案 1 :(得分:0)
默认参数确实会参与类型的推导,因此您会观察到行为。
或者,您可能会创建重载:
template <class UnaryPredicate>
int GetCountIf(const std::vector<int>& v, UnaryPredicate pred) {
int count = 0;
for (auto i: v) {
if (pred(i)) {
count++;
}
}
return count;
}
int GetCountIf(const std::vector<int>& v) {
return GetCountIf(v, [](auto) { return true; }); // return v.size(); // :-)
}