lambda的C ++模板类型推断

时间:2018-01-05 16:22:05

标签: c++ templates lambda

假设我有这个功能:

template <typename T>
T sum(std::vector<T> const& v) {
    T acc = T();
    for (auto const& e : v) {
        acc += e;
    }
    return acc;
}

这里C ++只允许用向量调用这个函数,并且可以自动推断T类型参数。

我有什么方法可以使用lambdas做同样的事情吗?我知道它们在语义上和functor一样,我可以轻松地在那里做到,但我对lambdas内联感兴趣。我知道我可以这样做:

[](auto& v) { ... }

但这匹配任何东西,甚至非矢量参数(即使正文导致编译器错误)。

2 个答案:

答案 0 :(得分:1)

在C ++ 20中,我们可以在捕获列表后面指定模板参数:

auto accum = []<class T>(std::vector<T>& v) {
    auto acc = T{};
    for (auto const& e : v) {
        acc += e;
    }
    return acc;
};

Demo

在临时假设现在你依靠类型特征来推断value_type

auto accum = [](auto& v) {
    auto acc = typename std::decay_t<decltype(v)>::value_type{};
    for (auto const& e : v) {
        acc += e;
    }
    return acc;
};

如果您想强制执行特定容器,则可以使用static_assert

auto accum = [](auto& v) {
    using ttype = std::decay_t<decltype(v)>;
    using vtype = typename ttype::value_type;
    static_assert(std::is_same_v<std::vector<vtype>, ttype>);
    auto acc = vtype{};

    for (auto const& e : v) {
        acc += e;
    }
    return acc;
};

例如:

int main(){

    std::vector<int> v{1,2,3};
    std::list<double> l{4.0,5.0,6.0};
    auto accum = [](auto& v) {
        auto acc = typename std::decay_t<decltype(v)>::value_type{};
        for (auto const& e : v) {
            acc += e;
        }
        return acc;
    };

    std::cout << accum(v) << std::endl;
    std::cout << accum(l) << std::endl;
}

Demo for any iterable container with a value_type

Demo with static_assert for vector type

既然您提到您没有使用STL容器,而是使用Phantom Types,那么您有两种选择:

  • 为强类型枚举添加typedef,如using value_type = PHANTOM_TYPE
  • 创建一个单独的traits类来推断value_type

    模板 struct SUInt { 上市:     SUInt(unsigned int value):m_value(value){}     内联unsigned int&amp; Value(){return m_value; } 私人的:     unsigned int m_value; };

    模板 struct SUInt_traits {};

    模板 struct SUInt_traits&gt; {     使用value_type = T; };

然后您可以在lambda like so中使用

auto do_a_thing = [](auto& v) {
    auto acc =  typename SUInt_traits<std::decay_t<decltype(v)>>::value_type{};
    // ...
};

答案 1 :(得分:0)

你可以使用带有std :: accumulate的lambda,虽然给出一个简单的总和,实际上并不需要lambda。