模板参数扣除使用元组在lambda上失败

Template argument deduction fails on lambda using tuple

本文关键字:元组 lambda 失败 参数      更新时间:2023-10-16

我正在尝试制作一个查询函数,使我可以查询一个stl容器以了解某些元素特征,然后返回结果集。实际上,这只是正常stl操作周围的句法糖(特别是copy_if和back_inserter)。

#include <string>
#include <tuple>
#include <functional>
#include <vector>
// This is the query function, it compiles fine
template<typename T, typename ... U>
T query(T const& input, std::function<bool(std::tuple<U...> const& row)> pred)
{
    T result;
    std::copy_if(std::begin(input), std::end(input), std::back_inserter(result), pred);
    return result;
}
// Define my Row, with each column having a type
using Row = std::tuple<int, float, std::string>;
int main()
{
    // Create a sample vector of Rows
    std::vector<Row> vec;
    for(size_t i = 0; i < 100; ++i)
        vec.emplace_back(i, 5.0f, "hello");
    // This is how I would perform the query 
    // **** This is the line that doesn't compile due to template arg deduction failure ****
    auto result = query(vec, [](Row const& row) -> bool { return true; });
    return 0;
}

这是编译器输出(Clang 3.3)

main.cpp:27:19: error: no matching function for call to 'query'
    auto result = query(vec, [](Row const& row) -> bool { return true; });
                  ^~~~~
main.cpp:8:3: note: candidate template ignored: failed template argument deduction
T query(T const& input, std::function<bool(std::tuple<U...> const& row)> pred)
  ^
1 error generated.

lambda不是std::function,它是一种具有重载operator()的类类型,两种类型是不同的类型。query函数需要一个std::function<...>参数,并且模板参数扣除需要类型是确切的匹配(除了CV-Qualifiers之外),因此永远不会将从lambda表达式转换为std::function的转换。

>

当然,一个解决方案是在调用query

之前构造std::function
auto result = query(vec, 
                    std::function<bool(Row const&)>(
                        [](Row const&) { return true; }));

另一个选择是更改您的功能本身

template<typename T, typename UnaryPredicate>
T query(T const& input, UnaryPredicate&& pred)
{
    T result;
    std::copy_if(std::begin(input), std::end(input), 
                 std::back_inserter(result), std::forward<UnaryPredicate>(pred));
    return result;
}

现在可以使用您的原始代码来称呼它。

实时演示