std::any 用于仅移动模板,其中 copy-ctor 内的 static_assert 等于编译错误,但为啥呢?
Posted
技术标签:
【中文标题】std::any 用于仅移动模板,其中 copy-ctor 内的 static_assert 等于编译错误,但为啥呢?【英文标题】:std::any for move-only template where static_assert inside copy-ctor equals compile error, but why?std::any 用于仅移动模板,其中 copy-ctor 内的 static_assert 等于编译错误,但为什么呢? 【发布时间】:2019-11-11 21:16:14 【问题描述】:我不明白为什么只有移动模板不能通过具有static_assert
(如下面的代码)的copy-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<:decay_t>> 为真时参与重载决议。
据我所知,std::is_copy_constructible<MoveOnly>::value
给出了 true 并且永远不会调用 copy-ctor。那么编译器怎么可能还在抱怨 static_assert
里面的 copy-ctor 呢?
【问题讨论】:
不是 100% 肯定,但我想std::any
与std::function
非常相似,因为它需要通过多态来实现,所以它别无选择,只能要求复制-其分配内容的可构造性。
@Frank 我明白这一点,他们用std::is_copy_constructible<MoveOnly>::value
进行检查,对吗?所以我设法将该值设置为 true,所以我看不出他们最终如何在不直接调用 copy-ctor 的情况下找出static_assert
。
我不明白这个问题。将选择 ctor #4,因为 std::is_copy_constructible_v<std::decay_t<ValueType>>
是 true
。这意味着你制作了一个副本,这意味着你的static_assert
会触发。
@NathanOliver-ReinstateMonica 不,据我所知,#4 仅在 std::is_copy_constructible_v<std::decay_t<ValueType>>
为 true
时启用。但是如果你使用 std::move
它仍然使用 move-ctor
该函数无论如何都会被创建,因为它被辅助类型的 vtable 指向。这是因为std::any
可能会被复制到其他翻译单元中的另一个std::any
。复制构造函数不会在您的代码中调用,但它可能会从其他地方调用。没有办法提前知道。
【参考方案1】:
考虑以下情况:
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
,所以我们别无选择,必须复制-构造函数可用以防万一它可能需要被调用。
编辑:解决 cmets 中提到的问题:
好的。那么我是否理解正确:复制ctor被创建并且static_assert被触发,因为一个简单的指针指向复制ctor?
本质上,是的。一旦一个指针指向一个函数,该函数就必须存在,并且使该函数存在将触发它的代码生成,包括评估其中的任何static_assert()
。
在您的理解中唯一有点偏离的是指针并不是为了它而存在的。它在那里是因为它很有可能被用来调用指向的函数。也许它会在 LTO 期间得到优化,但为时已晚;到那时code-gen就完成了
【讨论】:
以上是关于std::any 用于仅移动模板,其中 copy-ctor 内的 static_assert 等于编译错误,但为啥呢?的主要内容,如果未能解决你的问题,请参考以下文章
std::reference_wrapper<std::any> 上的类型特征