I don't see why move-only templates can not be extended by copy-ctor having a static_assert
(like in the code below) in order to be used with std::any
#include <any>
#include <cassert>
namespace detail{
template<typename T=int>
struct MoveOnly
{
MoveOnly() = default;
MoveOnly(MoveOnly const&) {static_assert(sizeof(T)!=sizeof(T),"");}
MoveOnly(MoveOnly &&) = default;
MoveOnly &operator=(MoveOnly const&) {static_assert(sizeof(T)!=sizeof(T),"");}
MoveOnly &operator=(MoveOnly &&) = default;
};
}
using MoveOnly = detail::MoveOnly<>;
static_assert(std::is_copy_constructible<MoveOnly>::value,"");
int main() {
MoveOnly a;
//std::any any(std::move(a)); //<- compile error
return 0;
}
In std::any::any it says for ctor #4
This overload only participates in overload resolution if ... std::is_copy_constructible_v<std::decay_t<ValueType>> is true.
As far as I can see std::is_copy_constructible<MoveOnly>::value
gives true and copy-ctor is never being called. So how is it possible that the compiler still complains about the static_assert
inside copy-ctor?
Consider the following case:
foo.h:
void foo(const std::any& v);
foo.cpp:
void foo(const std::any& v) {
std::any tmp = v;
}
main.cpp:
#include "foo.h"
int main() {
MoveOnly a;
std::any any(std::move(a));
foo(any);
return 0;
}
Inside of main.cpp
, there is no way of knowing whether foo()
will make a copy of v
or not, so we have no choice, there has to be a copy-constructor available just in case it might need to be invoked.
edit: To address something mentioned in the comments:
Ok. So do I understand this correct: The copy-ctor gets created and static_assert is being fired because a simple pointer is pointing to the copy-ctor?
In essence, yes. As soon as a pointer refers to a function, that function has to exist, and bringing that function into existence will trigger code-gen for it, including evaluating any static_assert()
within.
The only thing that's a little off in your understanding is that the pointer doesn't exist just for the heck of it. It's there because there's a real possibility that it might be used to invoke the pointed function. Maybe it will get optimized away during LTO, but that's too late; code-gen is finished by then