Я пытаюсь создать функцию, которая применяет произвольный функтор F
каждому элементу предоставленного кортежа:
#include <functional>
#include <tuple>
// apply a functor to every element of a tuple
namespace Detail {
template <std::size_t i, typename Tuple, typename F>
typename std::enable_if<i != std::tuple_size<Tuple>::value>::type
ForEachTupleImpl(Tuple& t, F& f)
{
f(std::get<i>(t));
ForEachTupleImpl<i+1>(t, f);
}
template <std::size_t i, typename Tuple, typename F>
typename std::enable_if<i == std::tuple_size<Tuple>::value>::type
ForEachTupleImpl(Tuple& t, F& f)
{
}
}
template <typename Tuple, typename F>
void ForEachTuple(Tuple& t, F& f)
{
Detail::ForEachTupleImpl<0>(t, f);
}
struct A
{
A() : a(0) {}
A(A& a) = delete;
A(const A& a) = delete;
int a;
};
int main()
{
// create a tuple of types and initialise them with zeros
using T = std::tuple<A, A, A>;
T t;
// creator a simple function object that increments the objects member
struct F
{
void operator()(A& a) const { a.a++; }
} f;
// if this works I should end up with a tuple of A's with members equal to 1
ForEachTuple(t, f);
return 0;
}
Пример живого кода: http://ideone.com/b8nLCy
Я не хочу создавать копии A
потому что это может быть дорого (очевидно, в этом примере это не так), поэтому я удалил конструктор копирования. Когда я запускаю вышеуказанную программу, я получаю:
/usr/include/c++/4.8/tuple:134:25: error: use of deleted function ‘A::A(const A&)’ : _M_head_impl(__h) { }
Я знаю, что конструктор удален (это было сделано намеренно), но я не понимаю, почему он пытается сделать копии моей структуры. Почему это происходит, и как я могу добиться этого без копирования A
?
Это проблема, вы получаете ошибку «удаленного конструктора» для:
std::function<void(A)> f = [](A& a) { a.a++; };
Вы пытаетесь настроить std::function
который проходит A
по значению. Но A
, не имеющий конструктора копирования, не может быть передан по значению.
Попробуйте сопоставить фактический тип аргумента более тщательно:
std::function<void(A&)> f = [](A& a) { a.a++; };
Но так как вы не захватываете переменные, вы можете просто попробовать
void(*f)(A&) = [](A& a) { a.a++; };
У вас также есть серьезная проблема с базовым вариантом рекурсии шаблона: даже если вы получаете enable_if
работая, что, кажется, не так, у вас будет неоднозначный вызов. Я думаю, что вам нужно также запрещать основной случай.
При создании экземпляра std::function<void(A)>
функция с подписью, принимающая A
по значению создается. Чтобы синтезировать это определение функции копию или ход A
нужно. поскольку A
не является копируемым, но не может быть перемещен, такого конструктора не существует.
Конечно, есть еще одна забавная вещь:
T t();
который объявляет функцию, возвращающую T
по значению требует копию. При звонке ForEachTuple(t, f)
эта функция ссылается и создается. Вы можете заменить это объявление одним из
T t;
T t{};
(в ответе выше я только посмотрел на первую обнаруженную проблему).