2017-01-16 11 views
1

Скажем, у меня есть эта функция: (что в значительной степени проходит функцию для каждого значения в контейнере, а затем возвращает вектор результата каждой итерации)Как вывести const и non-const тип без дублирующих функций?

#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); 

Поскольку parametered vector является const, чтобы это произошло, мне придется создать два vmap, которые получают не- constV и один, который const.

Он начинает чувствовать себя слишком много, когда несколько контейнеров/vector с переданы функции, потому что это заставляет меня писать функции 2^containers_count.

Есть ли какие-либо (-ногие, но рабочие) решения для этого?

ответ

4

Вы можете использовать ссылку переадресации для связывания с обеих нормальных ссылок л-значение (например, std::vector<int>&) и ссылки г-значение (std::vector<int>&&).

Недостатком является то, что вы никогда не в состоянии передать по значению (только реф, сопзЬ исх, или г-значение исх), хотя я не думаю, что это будет для вас проблемой:

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

Обратите внимание, что лямбда вы передаете должны быть применимы и к сопзЬ, если вы собираетесь передать константную контейнер (Спасибо, Майлз), так 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); 
+1

Re your note: Функтор должен быть применим только к 'const', если вы передадите контейнер' const'. [Пример] (http://coliru.stacked-crooked.com/a/858852c55432fb6c) –

+0

@MilesBudnek: справедливая точка – AndyG

+0

Это довольно близко, но когда я передаю 'lvalue', он не говорит, что это объект только для чтения. – LyingOnTheSky

1

Если вы хотите, чтобы ваши функции изменяли вектор, удалите const из параметров вашей функции. Константа v будет выведена из аргумента, который ей дается.

Вам также не нужно указывать тип возврата, он будет выведен из инструкции 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. Если вы хотите обобщить свой алгоритм, вам нужно будет удалить эту строку или специализироваться на ней.

+0

* Вам также не нужно указывать тип возврата, он будет выведен из оператора return. * Только в C++ 14, C++ 11 этого не делает. –

+0

Я получил: 'неправильная инициализация неконстантной ссылки типа 'std :: vector &' из rvalue типа 'std :: vector '' – LyingOnTheSky

+0

См. [Этот ответ] (http: // stackoverflow.com/a/41683306/7359094) от AndyG, поскольку это более полно. –

0

Вы можете использовать лямбду, которая принимает постоянный вектор. Для примера:

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

Или изменить vmap, что она не требует постоянного вектора. Для примера:

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