I have several classes for which I wish to check whether a default move constructor is being generated. Is there a way to check post-compile, whether these were generated?
I wish to avoid:
- tediously checking the conditions for implicit move ctor generation,
- explicitly and recursively defaulting the special member functions of all affected classes, their bases, and their members—just to make sure a move constructor is available.
I have already tried the following and they do not work:
- use
std::move
explicitly—this will invoke the copy ctor if no move ctor is available. - use
std::is_move_constructible
—this will succeed when there is a copy constructor acceptingconst Type&
, which is generated by default (as long as the move constructor is not explicitly deleted, at least). - use
nm -C
to check the presence of move ctor [see below].
I tried looking at the generated symbols of a trivial class like this:
#include <utility>
struct MyStruct {
MyStruct(int x) : x(x) {}
//MyStruct(const MyStruct& rhs) : x(rhs.x) {}
//MyStruct(MyStruct&& rhs) : x(rhs.x) {}
int x;
};
int main() {
MyStruct s1(4);
MyStruct s2(s1);
MyStruct s3(std::move(s1));
return s1.x+s2.x+s3.x; // make sure nothing is optimized away
}
The generated symbols looks like this:
$ CXXFLAGS="-std=gnu++11 -O0" make -B x; ./x; echo $?; nm -C x | grep MyStruct | cut -d' ' -f3,4,5
g++ -std=gnu++11 -O0 x.cc -o x
12
.pdata$_ZN8MyStructC1Ei
.pdata$_ZSt4moveIR8MyStructEONSt16remove_referenceIT_E4typeEOS3_
.text$_ZN8MyStructC1Ei
.text$_ZSt4moveIR8MyStructEONSt16remove_referenceIT_E4typeEOS3_
.xdata$_ZN8MyStructC1Ei
.xdata$_ZSt4moveIR8MyStructEONSt16remove_referenceIT_E4typeEOS3_
MyStruct::MyStruct(int)
std::remove_reference<MyStruct&>::type&&
The output is the same when I explicitly default the copy and move ctors (no symbols).
With my own copy and move ctors, the output looks like this:
$ vim x.cc; CXXFLAGS="-std=gnu++11 -O0" make -B x; ./x; echo $?; nm -C x | grep MyStruct | cut -d' ' -f3,4,5
g++ -std=gnu++11 -O0 x.cc -o x
12
.pdata$_ZN8MyStructC1Ei
.pdata$_ZN8MyStructC1EOKS_
.pdata$_ZN8MyStructC1ERKS_
.pdata$_ZSt4moveIR8MyStructEONSt16remove_referenceIT_E4typeEOS3_
.text$_ZN8MyStructC1Ei
.text$_ZN8MyStructC1EOKS_
.text$_ZN8MyStructC1ERKS_
.text$_ZSt4moveIR8MyStructEONSt16remove_referenceIT_E4typeEOS3_
.xdata$_ZN8MyStructC1Ei
.xdata$_ZN8MyStructC1EOKS_
.xdata$_ZN8MyStructC1ERKS_
.xdata$_ZSt4moveIR8MyStructEONSt16remove_referenceIT_E4typeEOS3_
MyStruct::MyStruct(int)
MyStruct::MyStruct(MyStruct&&)
MyStruct::MyStruct(MyStruct const&)
std::remove_reference<MyStruct&>::type&& std::move<MyStruct&>(MyStruct&)
So it appears this approach also doesn't work.
However if the target class has a member with explicit move constructor, the implicitly generated move constructor will be visible for the target class. I.e. with this code:
#include <utility>
struct Foobar {
Foobar() = default;
Foobar(const Foobar&) = default;
Foobar(Foobar&&) {}
};
struct MyStruct {
MyStruct(int x) : x(x) {}
int x;
Foobar f;
};
int main() {
MyStruct s1(4);
MyStruct s2(s1);
MyStruct s3(std::move(s1));
return s1.x+s2.x+s3.x; // make sure nothing is optimized away
}
I will get the symbol for MyStruct
's move ctor, but not the copy ctor, as it appears to be fully implicit. I presume the compiler generates a trivial inlined move ctor if it can, and a non-trivial one if it must call other non-trivial move ctors. This still doesn't help me with my quest though.
Aucun commentaire:
Enregistrer un commentaire