16

I'm trying to get along with std::function. From reference here one can see that argument to std::function's ctor should be callable and copy constructible. So here is small example:

#include <iostream>
#include <type_traits>
#include <functional>

class A {
public:
    A(int a = 0): a_(a) {}
    A(const A& rhs): a_(rhs.a_) {}
    A(A&& rhs) = delete;
    void operator() ()
    {
        std::cout << a_ << std::endl;
    }

private:
    int a_;
};

typedef std::function<void()> Function;

int main(int argc, char *argv[])
{
    std::cout << std::boolalpha;
    std::cout << "Copy constructible: "
              << std::is_copy_constructible<A>::value << std::endl;
    std::cout << "Move constructible: "
              << std::is_move_constructible<A>::value << std::endl;
    //Function f = A();
    return 0;
}

We have callable, copy constructible but not move constructible class. As I believe this should be sufficient to wrap it in Function. But if you uncomment commented line compiler becomes very upset about deleted move constructor. Here is ideone link. GCC 4.8.0 doesn't compile this too.

So, is it something I misunderstand about std::function or is it GCC's incorrect behaviour?

iw.kuchin
  • 738
  • 6
  • 14
  • Just tried with clang++, same problem there. – Some programmer dude Jul 25 '13 at 07:43
  • 3
    I _think_ the `delete`d function is still considered during overload resolution, and in this case is selected ahead of the copy constructor and causes the error. To correct, remove the declaration of the move constructor as one will not be implicitly generated due to the existence of the user declared constructor. Also, see [this question](http://stackoverflow.com/questions/16897845/move-member-function-generation) for `is_move_constructible` information. – hmjd Jul 25 '13 at 07:51
  • 1
    @hmjd Yup. http://stackoverflow.com/q/14085620/1171191 – BoBTFish Jul 25 '13 at 07:56

2 Answers2

11

GCC and Clang are correct.

§17.6.3.1.1 Template argument requirements [utility.arg.requirements]

Table 20MoveConstructible requirements [moveconstructible].

  • T u = rv; u is equivalent to the value of rv before the construction.
  • T(rv); T(rv) is equivalent to the value of rv before the construction.

Table 21CopyConstructible requirements (in addition to MoveConstructible) [copyconstructible].

  • T u = v; the value of v is unchanged and is equivalent to u.
  • T(v); the value of v is unchanged and is equivalent to T(v).

Note the:

CopyConstructible requirements (in addition to MoveConstructible)

I.e. if something is CopyConstructible it must also be MoveConstructible. Though it is fine to implement the move as a copy.

Update:

Though I find it interesting that the C++11 standard doesn't seem to define is_copy_constructible in terms of CopyConstructible, i.e. they are not quite the same, is_copy_constructible is more relaxed as it only requires:

§20.9.4.3 Type properties [meta.unary.prop]

Table 49 — Type property predicates

  • is_copy_constructible<T>; is_constructible<T,const T&>::value is true.
Community
  • 1
  • 1
ronag
  • 49,529
  • 25
  • 126
  • 221
4

You misunderstood the purpose of the delete specification. A move-constructor is not default-implemented. If you try to move an object without a move-ctor it will just be copied. If you specify the move-constructor as deleted it will try to call it and then see it's deleted. That means: You cannot copy a temporary object. Remove the move-constructor statement and it will work.

Edit - Clarification:

If no move-constructor is declared(where =delete is a declaration), then a construction from a temporary object will call the copy-constructor (from const reference). If you declare a move constructor a construction from a temporary object will try to call this. So if you declare a move-ctor deleted, it will try to call a delete function, which will result in an error. If you do not declare it, it will result in a call of the copy ctor.

That's why your example doesn't work, if you wouldn't have declared it std::function would just use the copy-ctor.

By default I meant: implemented if not declared, as it happens with the copy- or default-ctor.