g++ rejects the following well-formed code: template <class T> struct A { A() {} A(A const volatile &&) = delete; A &operator =(A const volatile &&) = delete; template <class U> A(A<U> &&) {} template <class U> A &operator =(A<U> &&) { return *this; } }; struct B { A<int> a; B() = default; B(B &&) = default; B &operator =(B &&) = default; }; int main() { B b = B(); b = B(); } The compiler says that the defaulted move functions in B are deleted, however 12.8/11 and 12.8/23 do not define such functions as deleted.
How are you calling g++? What version are you using? What is the diagnostic you get?
(In reply to comment #1) > How are you calling g++? /mingw-gcc-4.7.1/bin/g++ test.cpp -std=c++11 > What version are you using? Target: i686-pc-mingw32 Configured with: ../src/configure --prefix=/c/temp/gcc/dest --with-gmp=/c/temp/gcc/gmp --with-mpfr=/c/temp/gcc/mpfr --with-mpc=/c/temp/gcc/mpc --enable-languages=c,c++ --with-arch=i686 --with-tune=generic --disable-libstdcxx-pch --disable-nls --disable-shared --disable-sjlj-exceptions --disable-win32-registry --enable-checking=release --enable-lto Thread model: win32 gcc version 4.7.1 (GCC) > What is the diagnostic you get? test.cpp: In function 'int main()': test.cpp:25:17: error: use of deleted function 'B::B(B&&)' test.cpp:19:9: note: 'B::B(B&&)' is implicitly deleted because the default definition would be ill-formed: test.cpp:19:9: error: non-static data member 'B::a' does not have a move constructor or trivial copy constructor test.cpp:26:15: error: use of deleted function 'B& B::operator=(B&&)' test.cpp:20:12: note: 'B& B::operator=(B&&)' is implicitly deleted because the default definition would be ill-formed: test.cpp:20:12: error: non-static data member 'B::a' does not have a move assignment operator or trivial copy assignment operator
g++ v4.7.2 20120908 (prerelease) compiles the original example successfully, but it fails to compile the following code: template <class T> struct A { A() {} A(A const volatile &&) = delete; A &operator =(A const volatile &&) = delete; template <class U> A(A<U> &&) {} template <class U> A &operator =(A<U> &&) { return *this; } }; struct B { A<int> a; B() = default; }; int main() { B b = B(); b = B(); } Target: i686-pc-linux-gnu Configured with: ../configure --prefix=../target --enable-languages=c,c++ Thread model: posix gcc version 4.7.2 20120908 (prerelease) (GCC) COLLECT_GCC_OPTIONS='-v' '-std=c++11' '-shared-libgcc' '-mtune=generic' '-march=pentiumpro' ../target/libexec/gcc/i686-pc-linux-gnu/4.7.2/cc1plus -quiet -v -D_GNU_SOURCE test.cpp -quiet -dumpbase test.cpp -mtune=generic -march=pentiumpro -auxbase test -std=c++11 -version -o /tmp/cc0973J0.s GNU C++ (GCC) version 4.7.2 20120908 (prerelease) (i686-pc-linux-gnu) compiled by GNU C version 4.7.2 20120908 (prerelease), GMP version 5.0.2, MPFR version 3.1.0, MPC version 0.8.2 test.cpp: In function ‘int main()’: test.cpp:23:17: error: use of deleted function ‘B::B(const B&)’ test.cpp:15:12: note: ‘B::B(const B&)’ is implicitly deleted because the default definition would be ill-formed: test.cpp:15:12: error: use of deleted function ‘constexpr A<int>::A(const A<int>&)’ test.cpp:2:16: note: ‘constexpr A<int>::A(const A<int>&)’ is implicitly declared as deleted because ‘A<int>’ declares a move constructor or move assignment operator test.cpp:24:15: error: use of deleted function ‘B& B::operator=(const B&)’ test.cpp:15:12: note: ‘B& B::operator=(const B&)’ is implicitly deleted because the default definition would be ill-formed: test.cpp:15:12: error: use of deleted function ‘A<int>& A<int>::operator=(const A<int>&)’ test.cpp:2:16: note: ‘A<int>& A<int>::operator=(const A<int>&)’ is implicitly declared as deleted because ‘A<int>’ declares a move constructor or move assignment operator
The example can be simplified to struct A { A() {} A(A &&) = delete; A &operator =(A &&) = delete; }; struct B { A a; B() = default; }; int main() { B b = B(); b = B(); } I think this is ill-formed, so G++ is right to reject it. struct A cannot be moved because its move operations are deleted, and cannot be copied because the implicit-declared copy operations are defined as deleted, see [class.copy]/7. Therefore struct B cannot be moved or copied either.
(In reply to comment #4) These examples aren't similar. An implicitly defined move constructor performs direct-initialization of non-static data members with the corresponding members of the argument, which is interpreted as xvalue (12.8/15). In every such a direct-initialization all constructors are considered (13.3.1.3), including constructor templates. Template argument for the parameter U can be deduced as int, and the produced specialization of the constructor template will have better match than both copy and move constructors. Similarly for assignment operators. > struct A cannot be moved because its move operations are deleted This is not so in my example, and g++ correctly handles the following case: template <class T> struct A { A() {} A(A const volatile &&) = delete; A &operator =(A const volatile &&) = delete; template <class U> A(A<U> &&) {} template <class U> A &operator =(A<U> &&) { return *this; } }; int main() { A<int> a = A<int>(); // OK a = A<int>(); // OK }
(In reply to comment #5) > These examples aren't similar. You're right I reduced it too far, sorry. I'll confirm this then and CC Jason to look at it.
(In reply to comment #3) > g++ v4.7.2 20120908 (prerelease) compiles the original example successfully, > but it fails to compile the following code: G++ is following the proposed resolution of DR 1402 here; A<int> does not have a move constructor and it is not trivially copyable, so the B move constructor is not implicitly declared. This seems like a flaw in the 1402 drafting; the template constructor should count.
(In reply to comment #7) > (In reply to comment #3) > > g++ v4.7.2 20120908 (prerelease) compiles the original example successfully, > > but it fails to compile the following code: > > G++ is following the proposed resolution of DR 1402 here; A<int> does not have > a move constructor A<int> does have a move constructor, which is instantiated from A(A const volatile &&) = delete; See 12.8/3: A non-template constructor for class X is a move constructor if its first parameter is of type X&&, const X&&, volatile X&&, or const volatile X&&, and either there are no other parameters or else all other parameters have default arguments
Author: jason Date: Mon Sep 10 14:08:32 2012 New Revision: 191140 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=191140 Log: PR c++/54506 * decl.c (move_signature_fn_p): Split out from move_fn_p. * method.c (process_subob_fn): Use it. * cp-tree.h: Declare it. Added: trunk/gcc/testsuite/g++.dg/cpp0x/implicit14.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/cp-tree.h trunk/gcc/cp/decl.c trunk/gcc/cp/method.c trunk/gcc/testsuite/ChangeLog
Author: jason Date: Mon Sep 10 14:24:19 2012 New Revision: 191146 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=191146 Log: PR c++/54506 * decl.c (move_signature_fn_p): Split out from move_fn_p. * method.c (process_subob_fn): Use it. * cp-tree.h: Declare it. Added: branches/gcc-4_7-branch/gcc/testsuite/g++.dg/cpp0x/implicit14.C Modified: branches/gcc-4_7-branch/gcc/cp/ChangeLog branches/gcc-4_7-branch/gcc/cp/cp-tree.h branches/gcc-4_7-branch/gcc/cp/decl.c branches/gcc-4_7-branch/gcc/cp/method.c branches/gcc-4_7-branch/gcc/testsuite/ChangeLog
Fixed for 4.7.2.