std::任何只用于移动的模板,其中副本ctor内的static_assert等于编译错误,但为什么

std::any for move-only template where static_assert inside copy-ctor equals compile error, but why?

本文关键字:于编译 assert 编译 为什么 错误 static ctor 移动 只用于 任何 std      更新时间:2023-10-16

我不明白为什么只有移动模板不能由具有static_assert的复制ctor扩展(如下面的代码(以便与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;
}

在std::any::any中,它表示ctor#4

此重载仅在。。。std::is_copy_constructible_v<std::decay_t<值类型>gt;是真的。

据我所见,std::is_copy_constructible<MoveOnly>::value给出true,并且从未调用复制ctor。那么,编译器怎么可能仍然抱怨复制器中的static_assert呢?

考虑以下情况:

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;
}

main.cpp内部,无法知道foo()是否会复制v,因此我们别无选择,作为可用的复制构造函数,以防可能需要调用它。

编辑:要解决评论中提到的问题:

好的。那么,我是否正确理解这一点:创建了复制ctor,并且由于一个简单的指针指向复制ctor而触发了static_assert?

本质上,是的。一旦指针引用了一个函数,该函数就必须存在,并且使该函数存在将触发它的代码生成,包括评估其中的任何static_assert()

在你的理解中,唯一有点偏离的是,指针的存在并不是为了它。它之所以存在,是因为它确实有可能被用来调用指向的函数。也许它会在LTO期间得到优化,但为时已晚;代码生成在之前完成