error: use of deleted function. Why?

quant picture quant · Nov 5, 2014 · Viewed 33.5k times · Source

I am trying to create a function that applies an arbitrary functor F to every element of a provided tuple:

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

Live code example: http://ideone.com/b8nLCy

I don't want to create copies of A because it might be expensive (obviously in this example it is not) so I deleted the copy constructor. When I run the above program I get:

/usr/include/c++/4.8/tuple:134:25: error: use of deleted function ‘A::A(const A&)’
       : _M_head_impl(__h) { }

I know that the constructor is deleted (that was intentional) but what I don't understand is why it is trying to make copies of my struct. Why is this happening, and how can I achieve this without copying A?

Answer

Ben Voigt picture Ben Voigt · Nov 5, 2014

This is the problem you're getting a "deleted constructor" error for:

std::function<void(A)> f = [](A& a) { a.a++; };

You're trying to set up a std::function that passes an A by value. But A, having no copy-constructor, can't be passed by value.

Try matching the actual argument type more carefully:

std::function<void(A&)> f = [](A& a) { a.a++; };

But since you aren't capturing variables, you can simply try

void(*f)(A&) = [](A& a) { a.a++; };

You've also got a major problem with the base case of your template recursion: even if you get enable_if working, which it seems not to be, you'll have an ambiguous call. I think you need to also disable the main case.