2
#include <iostream>
#include <type_traits> 

struct Foo 
{
    Foo(Foo&& f) = delete;
};

int main()
{

    std::cout << std::is_move_constructible<Foo>::value; // output is 1

    std::cin.ignore();
}

Under msv2013 should I forgot something, or is there a bug ?

APPENDUM:

#include <iostream>
#include <type_traits> 

struct Foo 
{ 
    ~Foo(){}
};

int main()
{
    std::cout << std::is_move_constructible<Foo>::value;

    std::cin.ignore();
}

even with CTP this program produce an output of 1 (and c++ standard say the contrary), whereas the first example with CTP works fine.

Guillaume Paris
  • 10,303
  • 14
  • 70
  • 145

1 Answers1

5

Yes, it must be a bug.

is_move_constructible is defined in terms of is_constructible, which requires that a construction with the given parameters is well-formed, which is clearly not the case here.

[C++11: Table 49]: is_move_constructible<T>

is_constructible<T, T&&>::value is true

 

[C++11: 20.9.4.3/6]: Given the following function prototype:

template <class T>
typename add_rvalue_reference<T>::type create();

the predicate condition for a template specialization is_constructible<T, Args...> shall be satisfied if and only if the following variable definition would be well-formed for some invented variable t:

T t(create<Args>()...);

(A note that follows clarifies that create is used here to avoid the Most Vexing Parse for all Args.)

For the record, the output is 0 with GCC 4.8.


A similar bug with is_*constructible relating to abstract classes appears to have been fixed in mid-2013, and here's another one:

Posted by Microsoft on 18/09/2013 at 13:17 Hi,

Thanks for reporting this bug. We've fixed it, and the fix is available in VS 2013 RC.

In fact, we've overhauled , fixing all known bugs. You can read more about this here: http://blogs.msdn.com/b/vcblog/archive/2013/06/28/c-11-14-stl-features-fixes-and-breaking-changes-in-vs-2013.aspx

Stephan T. Lavavej
Senior Developer - Visual C++ Libraries
stl@microsoft.com

The changelog behind that link includes the following fix:

the is_constructible family of type traits behaving incorrectly with references (DevDiv#517460)

So, give this a go again in MSVS's November 2013 CTP.

Update: I'm told that this is fixed in the November CTP. Thanks Andy Prowl for testing.

Community
  • 1
  • 1
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • Sorry, I provided a wrong information (messed up with project settings). It seems to be fixed in November 2013's CTP. – Andy Prowl Dec 28 '13 at 15:21
  • besides i think msvc2013 still doesn"t generate an implicit move ctor – Guillaume Paris Dec 28 '13 at 15:29
  • 1
    @Guillaume07: Indeed it doesn't. The CTP fixed that. – Andy Prowl Dec 28 '13 at 15:51
  • @Andy: but even with the CTP, if I declare `struct Foo` with a trivial destructor `std::is_move_constructible::value` return me true. And I believed than c++ standard establish than when a destructor is declared no implicit move ctor is generated – Guillaume Paris Dec 28 '13 at 20:00
  • @Guillaume07: That's how it should be, yes. Before they were never implicitly generating move-constructors and move-assignment operators, now they generate them too often. It's a swinging pendulum, hopefully VC13 will get this right :) – Andy Prowl Dec 28 '13 at 20:04
  • 1
    @Guillaume07: Actually, the reason why it returns `true` is that there is an implicitly generated copy constructor, and a copy-constructible class is also move-constructible. Now the implicit generation of a copy constructor is only deprecated, not illegal (because of backwards compatibility), so the CTP's behavior is still compliant. Try deleting the copy constructor: `std::is_move_constructible::value` should then yield `false`. – Andy Prowl Dec 28 '13 at 20:09
  • @Andy: ok I ignore the consequence of a copy-constructible class. Besides If I only declare the move-ctor + default ctor and attempt to copy Foo, MSVC2013 tell me that Foo(const Foo&) is deleted. – Guillaume Paris Dec 28 '13 at 20:16
  • @Guillaume07: That's because a user-declared move constructor inhibits the implicit generation of a copy constructor (12.8/7). Here, however, implicit generation is not deprecated but invalid: backwards compatibility does not apply, because move constructors did not exist before C++11 (more precisely, the copy constructor is implicitly defined as deleted). – Andy Prowl Dec 28 '13 at 20:19
  • @Andy:all right so there is the following asymmetry: a copy-constructible class is also move-constructible but a move-constructible class is not copy-constructible (except if user explicitly define both ctor). – Guillaume Paris Dec 28 '13 at 20:25
  • 1
    @Guillaume07: That's one of those areas where I think the Standard is quite misleading. The `MoveConstructible` concept means that you should be able to construct the object from an rvalue. The `CopyConstructible` concept means you should be able to construct the object from an lvalue. Now since a copy constructor accepts its argument by `const&` (let's forget about weird copy constructors that don't), you can pass an rvalue to it. You will get a copy, but that makes the class `MoveConstructible`. – Andy Prowl Dec 28 '13 at 20:30
  • 1
    @Guillaume07: Another way to think about it is in terms of state propagation. Copy is a way of propagating state from object X to object Y so that (1) object Y assumes the state of object X, and (2) object X retains its state. After the copy, both objects have the same state. Move is a way of propagating state that only requires (1), and that makes it more general. This is why `CopyConstructible` is a specialization of `MoveConstructible`, and not vice versa. This concept of "move" conflicts with the notion of "move" as "invoking the move constructor", and the Standard does not disambiguate. – Andy Prowl Dec 28 '13 at 20:32
  • @AndyProwl:thanks for these explanations, very clear. – Guillaume Paris Dec 28 '13 at 20:37