Есть ли привязка для контейнеров? - PullRequest
0 голосов
/ 13 мая 2018

В стандартной библиотеке C ++ allocators можно восстановить.

std::allocator<int>::rebind<double>::other дает std::allocator<double>.

Есть ли простой способ сделать это с контейнерами?

Причина в том, что у меня естьфункция, которая умножает элементы контейнера на скаляр.

template<class Container, typename S>
auto elementwise_multiply_by_scalar(Container const& c, S s){
    Container ret(c.size());
    for(auto& e : ret) e *= s;
    return ret;
}

Но если e * s не совпадает с типом e, я хочу сделать это:

template<class Container, typename S>
auto elementwise_multiply_by_scalar(Container const& c, S s){
    Container::rebind<decltype(Container::value_type{}*s)> ret(c.size());
    auto it2 = ret.begin();
    for(auto it1 = c.begin(); it1 != c.end(); ++it1, ++it2) *it2 = s * *it1;
    return ret;
}

(Iдумаю, не ясно, почему я хотел бы, чтобы выходные данные были того же класса контейнера, что и входные данные, но я предполагаю, что это ожидаемый результат.)

Я мог бы использовать аргументы шаблона шаблона (как в template<template<typename> class V>) но, похоже, у него тоже есть свои проблемы.

Нужен ли нам какой-то container_traits<V>::rebind?(например container_traits<std::vector<double, myallocator<double> >>::rebind<int>::other -> std::vector<int, myallocator<double>::rebind<int>::other>)

1 Ответ

0 голосов
/ 13 мая 2018

Примерно так может работать:

struct A
{
};

struct B
{
};

struct C
{
};

C operator *(const A&, const B&)
{
    return C();
}

template <typename Container, typename ValueType>
struct ContainerConverter
{
};

template <typename SourceValueType, typename ValueType>
struct ContainerConverter<std::vector<SourceValueType>, ValueType>
{
    typedef typename std::vector<ValueType> result_type;
};

template <typename Container, typename S>
auto mult(const Container& c, const S& s)
{
    typedef typename Container::value_type source_element;
    typedef decltype(c.front()*s) result_element;
    typename ContainerConverter<Container, result_element>::result_type result;
    std::transform(c.begin(), c.end(), std::back_inserter(result), [&](const source_element& e){ return e * s; } );
    return result;
}

int main()
{
    std::vector<A> a;
    std::vector<C> c = mult(a, B());
}

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

Если ваши контейнеры не поддерживают всеstd::back_inserter см. std :: преобразовать в произвольный контейнер .

...