I'd like to initialize std::any
with a move only type variable. I found Cannot move std::any.
Compile error case
Before I use shared_ptr workaround from the linked answer, I tested the following code:
#include <utility>
#include <iostream>
#include <any>
struct move_only {
move_only() {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
move_only(move_only const&) = delete;
move_only(move_only &&) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
int main() {
move_only m;
std::any a(std::move(m)); // error. copy constructor is required
}
https://wandbox.org/permlink/h6HOSdgOnQYg4a6K
The code above outputs compile error because of move_only
doesn't have copy constructor.
Add copy constructor for test
I added copy constructor for test.
#include <utility>
#include <iostream>
#include <any>
struct move_only {
move_only() {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
move_only(move_only const&) {
// not called
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
move_only(move_only &&) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
int main() {
move_only m;
std::any a(std::move(m)); // success but copy constructor is not called
}
https://wandbox.org/permlink/kxEnIslmVnJNRSn6
Then compile successfully finished as I expected. And I got interesting output.
move_only::move_only()
move_only::move_only(move_only &&)
It seems that the copy constructor isn't called. It is surprising for me.
And I come up with the following wrapper approach.
Add dummy copy constructor wrapper
#include <utility>
#include <iostream>
#include <any>
struct move_only {
move_only() {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
move_only(move_only const&) = delete;
move_only(move_only &&) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
struct wrapped_move_only : move_only {
wrapped_move_only(move_only&& m):move_only(std::move(m)) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
wrapped_move_only(wrapped_move_only const&) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
assert(false);
}
wrapped_move_only(wrapped_move_only &&) = default;
};
int main() {
move_only m;
wrapped_move_only wmo(std::move(m));
std::any a(std::move(wmo));
}
https://wandbox.org/permlink/EDhq3KPWKP9fCA9v
The copy constructor of move_only is deleted. The class wapped_move_only inherits move_only and added copy constructor.
It successfully compiled and I got the following result.
move_only::move_only()
move_only::move_only(move_only &&)
wrapped_move_only::wrapped_move_only(move_only &&)
move_only::move_only(move_only &&)
It seems that I initialized std::any with move only type using the wrapper that provides dummy copy constructor. It is more efficient to use shared_ptr if the goal is just initialize std::any with move only type. It is expected behavior for me.
As long as I do move operation only for std::any
once move_only
is moved to std::any
, is this code safe?
If std::any
is copied, then assetion failed due to copy constructor of wrapped_move_only is called. I want to know move only case's safety.
I am also not sure why std::any
's target requires copy constructor but it is not called.
templatized
If it is safe, I can improve this approach using template. The template add_dummy_copy_constructor
is a kind of adaptor.
#include <utility>
#include <iostream>
#include <any>
struct move_only {
move_only() {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
move_only(move_only const&) = delete;
move_only(move_only &&) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
template <typename T>
struct add_dummy_copy_constructor : T {
add_dummy_copy_constructor(T&& t):T(std::move(t)) {}
add_dummy_copy_constructor(add_dummy_copy_constructor const&) {
assert(false);
}
add_dummy_copy_constructor(add_dummy_copy_constructor &&) = default;
};
int main() {
move_only m;
std::any a(add_dummy_copy_constructor(std::move(m)));
}
std::any
's copy constructor conditionally enable/disable depends on actual type but I realized thatstd::any
is type erased type. The actual type is decided at run time.std::any
provides copy constructor is reasonable choice. So the actual type need to have copy constructor. – Dougald