Guillaume Paris
Guillaume Paris

Reputation: 10539

Move constructor and char array argument

struct Foo
{
    char data[100];

    template<int T>
    Foo(char (&&var)[T])
    {
        data = std::move(var);
        var = 0;
    } 
};

int main()
{ 
    char v[100];
    //..init v
    Foo f( std::move(v) );   //error C2664: 'Foo::Foo<100>(char (&&)[100])' : cannot convert parameter 1 from 'char [100]' to 'char (&&)[100]'
    return 0;
} 

I don't get why MSVC is not happy with the line Foo f( std::move(v) ) ? (Maybe this code is senseless)

Upvotes: 2

Views: 2470

Answers (2)

Cassio Neri
Cassio Neri

Reputation: 20523

The line

Foo f( std::move(v) );

is legal for GCC, Clang and Intel. Visual Studio however complains and yields

error C2664: 'Foo::Foo(const Foo &)' : cannot convert parameter 2 from 'char [100]' to 'char (&&)[100]'
1>          You cannot bind an lvalue to an rvalue reference

This seems a bug to me. Indeed, v is an lvalue but std::move cast it to an rvalue reference.

Since arrays of chars are not movable, although legal, I don't see much use for taking them by rvalue reference. If you really want the code to compile, a workaround is making f taking a regular (lvalue) reference and remove the std::move at the call site. Or even better, make f take a pointer to char* (f doesn't need to be a template). In this case, calling f(v) passes the address of v[0] (i.e. the first element of v) to f. This is the so called array-to-pointer conversion which is implicitly performed by the compiler.

However, as others have pointed out, the lines

    data = std::move(var);
    var = 0;

are illegal for all compilers. data and var are arrays (or references to arrays) and arrays are not assignable. For instance, the error raised by var = 0; by each compiler is as follows:

GCC:

error: incompatible types in assignment of 'int' to 'char [100]'

Clang:

error: array type 'char [100]' is not assignable

Intel:

error: expression must be a modifiable lvalue

Visual Studio:

error C2440: '=' : cannot convert from 'int' to 'char [100]'

Upvotes: 2

juanchopanza
juanchopanza

Reputation: 227448

You could use the std::move algorithm, from the <algorithm> header.

auto it = std::move(data, data + T, var);

after checking that T isn't larger than 100. But moving char doesn't have many benefits over just copying.

Upvotes: 2

Related Questions