Функциональный C ++ через злоупотребление шаблоном

Я решил попытаться написать реализацию функциональной карты на C ++ с использованием шаблонов, и вот что я придумал:

template <
class U,
class V,
template <class> class T
>

class T<V> WugMap(
class T<U>::const_iterator first,
class T<U>::const_iterator second,
V (U::*method)() const)

{
class T<V> collection;
while (first != second)
{
collection.insert(collection.end(), ((*(first++)).*method)());
}
return collection;
}

Теперь это все прекрасно и денди, и даже компилируется. Проблема в том, что я понятия не имею, как на самом деле это назвать.

Попытка наивного способа приводит к следующей ошибке:

prog.cpp:42: error: no matching function for call to
‘WugMap(__gnu_cxx::__normal_iterator<Container*, std::vector<Container,
std::allocator<Container> > >, __gnu_cxx::__normal_iterator<Container*,
std::vector<Container, std::allocator<Container> > >, int (Container::*)()const)’

Насколько я могу судить, все аргументы верны. gcc вообще не предлагает никаких альтернатив, что заставляет меня полагать, что мое определение WugMap является подозрительным, но оно компилируется нормально, так что я скорее заблудился. Кто-нибудь может направить меня через эту глупость?

Если кто-нибудь может предложить лучший способ написания такой функции, которая будет поддерживать использование любого типа коллекции, содержащей любой тип объекта, я постараюсь изменить его.

Вот мой идеон до сих пор.

В настоящее время я использую Ideone, который использует C ++ 03, GCC 4.3.4.

Возможно ли это в C ++ 11? Намекнули, что это так. Я знаю, что шаблоны в C ++ 11 поддерживают различное количество аргументов, поэтому я также изменю свои требования в соответствии с этим. Я приложу немного усилий, чтобы что-то написать, но пока вот требования, которые я ищу:

  • Должна иметь подпись что-то вроде следующего:

    C2<V, ...> map(const C1<U, ...>&, V (U::*)(...), ...)
    

    Это берет некоторую коллекцию C1, содержащую элементы типа U, сконструированные с некоторым количеством параметров по умолчанию, по ссылке, а также берет некоторую функцию-член (возвращающую V и принимающую некоторое количество аргументов неизвестных типов) из U, и затем принимающую, в порядок, аргументы для передачи функции-члену. Функция, наконец, вернет коллекцию типа C2, содержащую элементы типа V и инициализируемую с неизвестным количеством параметров по умолчанию.

  • Должен быть цепным:

    vector<int> herp = map(
    map(
    set<Class1, myComparator>(),
    &Class1::getClass2, 2, 3),
    &Class2::getFoo);
    
  • Бонусные баллы, если у меня нет необходимости использовать аргументы шаблона или другие подробности при его использовании.

std::transform отлично, но не цепной.

5

Решение

Аргументы шаблона никогда не могут быть выведены из вложенных типов. Даже если U а также V может быть выведен из указателя функции-члена, вы не сможете определить тип шаблона T,

Явное указание аргументов шаблона, как в ссылке на ideone (Я не делал ссылку до написания приведенного выше утверждения) тоже не работает, главным образом потому, что аргументы шаблона для std::vector не просто один тип T! std::vector принимает тип значения и тип распределителя. Исправление становится довольно уродливым:

#include <vector>
#include <iostream>

using namespace std;

class Container
{
public:
Container() {}
Container(int _i) : i(_i) {}

int get_i() const {return i;}

int i;
};

template <
class U,
class V,
template <typename...> class T
>

T<V> WugMap(
typename T<U>::const_iterator first,
typename T<U>::const_iterator second,
V (U::*method)() const)
{
T<V> collection;
while (first != second)
{
collection.insert(collection.end(), ((*(first++)).*method)());
}
return collection;
}

int main()
{
vector<Container> containers;
for (int i = 0; i < 10; ++i) containers.push_back((Container(i)));

WugMap<Container, int, std::vector>(
containers.begin(), containers.end(), &Container::get_i);
}
4

Другие решения

Не совсем уверен, должен ли это быть ответ, но черт возьми:

std::vector<std::string> src = f();
std::vector<std::string::size_type> sizes;
sizes.reserve(src.size());
// Actual transformation:
std::transform( src.begin(), src.end(), std::back_inserter(sizes),
[](std::string const& s) { return s.size(); } );

Подобные вещи можно сделать вручную, но в действительности нет смысла изобретать заново изобретенное колесо.

Что касается того, что отличается в std::transform случай, он не пытается связать типы так тесно, это требует Iter1 для первых двух аргументов, Iter2 для третьего аргумента и Functor для третьего. На интерфейсе нет никаких проверок, чтобы гарантировать, что Iter1 а также Iter2 итераторы в один и тот же тип контейнера, или что Functor преобразуется из типа значения в первом контейнере в тип значения во втором.

2

По вопросам рекламы [email protected]