"pair::operator=(pair&&)"错误,"auto&"推断出移动操作 - libstdc++ 回归?
`pair::operator=(pair&&)` error with `auto&` deduced move operations - libstdc++ regression?
给定此程序:
struct Val
{
Val() = default;
Val(Val&&) = default;
auto& operator=(Val&&);
};
/* PLACEHOLDER */
auto& Val::operator=(Val&&) { return *this; }
用…替换/* PLACEHOLDER */
。。。
int main()
{
std::vector<std::pair<int, Val>> v;
v.emplace(std::begin(v), 0, Val{});
}
成功编译于:
- g++6.2.0
- g++6.3.0
g++7.0.1(主干)
叮当++3.9.1
- 叮当++5.0.0(头部)
在wandbox上
用…代替/* PLACEHOLDER */
。。。
template <typename TVec>
void a(TVec& v)
{
v.emplace(std::begin(v), 0, Val{});
}
int main()
{
std::vector<std::pair<int, Val>> v;
a(v);
}
成功编译于:
- g++6.2.0
- 叮当++3.9.1
。。。但是在上产生编译时错误
- g++6.3.0
- g++7.0.1(主干)
- 叮当++5.0.0(头部)
在wandbox上
产生的错误似乎与受约束的pair operator=(pair&&)
过载有关——来自GitHub的libstdc++镜像上的include/bits/stl_pair.h
:
pair&
operator=(typename conditional<
__and_<is_move_assignable<_T1>,
is_move_assignable<_T2>>::value,
pair&&, __nonesuch&&>::type __p)
noexcept(__and_<is_nothrow_move_assignable<_T1>,
is_nothrow_move_assignable<_T2>>::value)
{
first = std::forward<first_type>(__p.first);
second = std::forward<second_type>(__p.second);
return *this;
}
用std::true_type
替换is_move_assignable<_T2>
可以编译代码。
将Val::operator=(Val&&)
的定义移到/* PLACEHOLDER */
之前可以编译代码。
将auto& Val::operator=(Val&&)
更改为Val& Val::operator=(Val&&)
可以编译代码。
这里发生了什么?这是最新版本的libstdc++中的实现缺陷吗?还是旧版本错误地编译了格式错误的代码
EDIT:正如AndyG在他的(现已删除)应答中发现的那样,在调用emplace
:之前调用空函数时也会发生错误
template <typename TVec>
void a(TVec&) { }
int main()
{
std::vector<std::pair<int, Val>> v;
a(v);
v.emplace(std::begin(v), 0, Val{});
}
用上面的a(v);
进行通信可以防止产生编译时错误这种行为在g++7和clang++5中都存在。
在wandbox上
另一个奇怪的案例是由Sergey Murzin发现的,可以在wandbox上进行测试:
int main()
{
std::vector<std::pair<int, Val>> v;
v.emplace(v.begin(), 0, Val{});
std::cout << v.back().first << std::endl;
}
上面的代码会产生编译器错误。注释掉包含std::cout
的行可以防止错误的发生这种行为在g++7和clang++5中都存在。
这几乎可以肯定是实例化问题。如果您做了一些触发pair<int, Val>
的定义在main
中实例化的事情,那么您就会得到错误。否则,它只在vector::emplace
被实例化时被实例化,这里讨论的实现将其推迟到翻译单元的末尾(这是允许的,请参见[temp.point]/8),在这一点上,赋值运算符是完全定义和可调用的。
CCD_ 17触发CCD_ 18定义的实例化,因为它是ADL所必需的。如果您写入::a(v)
或(a)(v)
(均抑制ADL),则错误将消失。(显然,a.back().first
需要pair<int, Val>
的实例化:您正在访问其数据成员。)
- 将对象移动到std::shared_ptr
- 何时在引用或唯一指针上使用移动语义
- 是否需要删除包含对象的"pair"?
- 如何从具有移动语义的类对象中生成共享指针
- 将shared_ptr移动到<StructA>shared_ptr<变体<结构A、结构 B>>
- C / C++ 移位/偏移/向左或向右移动位图?
- MSVC将仅移动结构参数解释为指针
- 自定义先决条件对移动分配运算符有效吗
- 返回值优化:显式移动还是隐式
- 当有分配器意识的容器被复制/移动时,反弹分配器是否被复制/移走
- 为什么复制而不是移动数据元素?
- 可以使用移动语义更改或改进此C++代码吗?
- 在我的代码中,获得最大的Pair Wise产品C++和输出并不总是正确的
- 使lambda不可复制/不可移动
- c++在使用指针时移动语义
- 将QGraphicsItem的移动区域限制在多边形区域内
- 为什么大多数 pair 实现默认不使用压缩(空基优化)?
- SendInput()鼠标移动计算
- "pair::operator=(pair&&)"错误,"auto&"推断出移动操作 - libstdc++ 回归?
- 在std::pair中存储不可复制(但可移动)的对象