Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Explicitly defaulted constructors in empty and non-empty struct

Tags:

c++

The following program compiles only if I pass the -DA=1 flag to the compiler:

#include <iostream>
#include <vector>
#include <algorithm>

struct element {
    element() = default;

    element(element&&) = default;
    element& operator=(element&&) = default;

    element(const element&) = delete;
    element& operator=(const element&) = delete;

    #if A
    std::vector<int> v;
    #endif
};

int main() {
    std::vector<element> source(10), destination;
    std::move(std::begin(source), std::end(source), std::back_inserter(destination));
}

If -DA=0 is passed then compilation fails with the error:

stl_algobase.h:373:4: error: static assertion failed: type is not assignable

Check it out on Coliru.

It fails when using GCC 4.9 or Clang 3.4.

Does the presence of a member variable affect the behavior of explicitly defaulted constructors?

Update

I was using stdlibc++ for both GCC and Clang. The code compiles when using Clang 3.4 and libc++.

like image 913
StackedCrooked Avatar asked Jul 09 '14 00:07

StackedCrooked


1 Answers

This version of std::move is:

template<class InputIterator, class OutputIterator>
    OutputIterator move(InputIterator first, InputIterator last,
    OutputIterator result);

OutputIterator properties are defined by [output.iterators], in particular the following expression must be valid:

*r = o

where r is the output iterator.

Based on the error messages shown by Coliru, it appears as if the library is checking std::is_copy_assignable<element>, which is of course false.

This appears to be a bug; the move ought to work using the move-assignment operator.

Compare the following in the same Coliru:

int main() {
    std::vector<element> e(1);
    std::vector<element> d(1);

    *e.begin() = std::move( *d.begin() );       // A=1 OK   A=0 OK
    std::move(d.begin(), d.end(), e.begin());   // A=1 OK   A=0 errors
}

The definition of std::move (3 arguments) includes that for each index it performs *(result + n) = std::move( *(first + n) ); . So if my first line is valid then my second line should also be valid.

like image 103
M.M Avatar answered Oct 15 '22 08:10

M.M