无法从函数参数的默认参数推断模板参数

Couldn't deduce template parameter from function parameter's default argument

本文关键字:参数 默认 函数      更新时间:2023-10-16

我正在尝试创建一个函数,该函数在满足给定条件的范围内找到最小元素:

#include <functional>
#include <iostream>
#include <vector>
template <typename It, typename Pred, typename Comp>
It minElementWhere(
    It begin,
    It end,
    Pred pred = Pred(),
    // Use less-than as the default comparator.
    Comp comp = std::less<decltype(*std::declval<It>())>()
) {
    It minElement = end;
    for (It it = begin; it != end; ++it) {
        if (!pred(*it)) {
            continue;
        }
        if (comp(*it, *minElement)) {
            minElement = it;
        }
    }
    return minElement;
}
int main() {
    std::vector<double> foo;
    foo.push_back(6);
    foo.push_back(10);
    foo.push_back(-3);
    foo.push_back(7);
    std::cout << *minElementWhere(
        foo.begin(),
        foo.end(),
        [](double val) {
            return val >= 0;
        }
    ) << std::endl;
}

但是我得到这个错误:

main.cpp: In function 'int main()':
main.cpp:40:5: error: no matching function for call to 'minElementWhere(std::vector<double>::iterator, std::vector<double>::iterator, main()::__lambda0)'
     ) << std::endl;
     ^
main.cpp:40:5: note: candidate is:
main.cpp:6:4: note: template<class It, class Pred, class Comp> It minElementWhere(It, It, Pred, Comp)
 It minElementWhere(
    ^
main.cpp:6:4: note:   template argument deduction/substitution failed:
main.cpp:40:5: note:   couldn't deduce template parameter 'Comp'
     ) << std::endl;

Comp不是返回类型,所以它没有试图推断返回类型,而且在我看来,Comp似乎没有模棱两可的重载(因为只能有一种解引用It的返回类型)。为什么我得到这个错误,我如何修复它?

您期望模板参数Comp从您为相应的函数参数提供的默认参数中推导出来。然而,它被显式地列为非推导上下文,这意味着该模板形参的模板实参推导将失败(除非它可以从其他地方推导出来)。

从<<p> em>§14.8.2.5/5 [temp.deduct.type]

未推断的上下文为:
-…
—A的参数类型中使用的模板参数中使用的默认实参的函数形参正在为其进行实参演绎的调用。

要成功演绎模板实参,需要为模板形参提供默认实参,而不是函数形参。

template <typename It, 
          typename Pred, 
          typename Comp = std::less<decltype(*std::declval<It>())>>
It minElementWhere(
    It begin,
    It end,
    Pred pred = Pred(),
    Comp comp = Comp()
) {
...
}

现场演示

您可能需要以下内容:

#include <iterator>
struct always_true{
    template<typename T>
    bool operator()(T&& val) const{
        return true;
    }
};
template <
    typename It, 
    typename Pred = always_true,
    typename Comp = std::less<typename std::iterator_traits<It>::value_type >
>
It minElementWhere(
    It begin,
    It end,
    Pred pred = Pred(),
    Comp comp = Comp()
    ){
    It minElement = end;
    for (It it = begin; it != end; ++it) {
        if (pred(*it) && (minElement == end || comp(*it, *minElement))){
            minElement = it;
        }
    }
    return minElement;
}

这个适合我:

template <typename It, typename Pred,
          typename Comp = std::less<decltype(*std::declval<It>())>>
It minElementWhere(
    It begin,
    It end,
    Pred pred = Pred(),
    Comp comp = Comp()
) {
    It minElement = end;
    for (It it = begin; it != end; ++it) {
        if (!pred(*it)) {
            continue;
        }
        if (comp(*it, *minElement)) {
            minElement = it;
        }
    }
    return minElement;
}