【问题标题】:How to deduce const and non-const type without duplicating functions?如何在不复制函数的情况下推断 const 和非 const 类型?
【发布时间】:2017-01-16 18:50:03
【问题描述】:

假设我有这个函数:(它几乎对容器中的每个值运行一个函数,然后返回每次迭代结果的向量)

#include <vector>
using std::vector;

template<class F, class V>
auto vmap(const F &f, const V &v) -> vector<decltype(f(v[0]))> {
    vector<decltype(f(v[0]))> result;
    result.reserve(v.size());
    for (auto &p : v)
        result.push_back(f(p));
    return result;
}

我不能这样称呼它:

vector<int> vint = {1,2,3,4,5};
vmap([](auto &p) {return p++;},vint);

因为参数化的vectorconst,为了实现它,我必须创建两个vmap 得到非const V 和一个const

当有多个容器/vectors 传递给一个函数时开始感觉太多了,因为它让我写2^containers_count 函数。

是否有任何(-肮脏但有效的)解决方案?

【问题讨论】:

    标签: c++ templates constants template-argument-deduction


    【解决方案1】:

    您可以使用转发引用来绑定普通左值引用(例如std::vector&lt;int&gt;&amp;)和右值引用(std::vector&lt;int&gt;&amp;&amp;)。

    缺点是您永远无法按值传递(仅 ref、const ref 或 r-value ref),尽管我认为这对您来说不是问题:

    template<class F, class V>
    auto vmap(F&& f, V&& v) {
        vector<decltype(f(v[0]))> result;
        result.reserve(v.size());
        for (auto& p : v)
            result.push_back(f(p));
        return result;
    }
    

    Demo

    请注意,如果您要传递一个 const 容器(谢谢,Miles),您传递的 lambda 必须同时适用于这两个 const,所以 p++ 是不可能的(尽管要注意一个模板实例化会修改输入而另一个没有,这可能是出乎意料的):

    vector<int> vint = {1,2,3,4,5};
    vmap([](auto &p) {return p++;},vint);
    const std::vector<int> vint2 = vint;
    vmap([](auto &p) {return p+1;},vint2);
    

    【讨论】:

    • 请注意:如果您传递 const 容器,则函子只需适用于 constExample
    • 非常接近,但是当我通过 lvalue 时,它并没有说它是只读对象。
    • @LyingOnTheSky:你能澄清一下你的意思吗?
    • @AndyG vmap([](auto &amp;p){return p++;},vector&lt;int&gt;()),当我这样做时,编译器不会对我大喊。 (如你所说,我需要传递参考)
    • @LyingOnTheSky:为什么要这样做?在构造函数中传递vector&lt;int&gt;() 会创建一个右值,您可以在函数中为其构造一个右值引用(std::vector&lt;int&gt;&amp;&amp;)。
    【解决方案2】:

    如果您想允许您的函数修改向量,请从您的函数参数中删除constv 的常量将从给它的参数中推导出来。

    你也不需要指定返回类型,它会从return语句中推导出来。

    template<class F, class V>
    auto vmap(const F &f, V &v) {
        vector<decltype(f(v[0]))> result;
        result.reserve(v.size());
        for (auto&p : v)
            result.push_back(f(p));
        return result;
    }
    

    请注意,result.reserve(v.size()); 仅适用于 std::vector。如果您想概括您的算法,您需要删除该行,或者专门针对它。

    【讨论】:

    • 你也不需要指定返回类型,它会从return语句中推导出来。 只有c++14,c++11没有。
    • 我得到了:invalid initialization of non-const reference of type ‘std::vector&lt;int&gt;&amp;’ from an rvalue of type ‘std::vector&lt;int&gt;’
    • 参见 AndyG 的 this answer,因为它更完整。
    【解决方案3】:

    您可以使用带有常数向量的 lambda。 以您为例:

    vmap([](const auto &p) {return p+1;}, vint);
    

    或者修改vmap,使其不需要常量向量。 以您为例:

    auto vmap(const F &f, V &v)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-09
      • 2023-02-04
      • 2021-12-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多