#include <unordered_map>
#include <type_traits>
int main()
{
std::unordered_multimap<int, string> m{ { 1, "hello" } };
auto b = std::is_move_assignable_v<decltype(*m.begin())>;
// b is true
auto v = *m4.begin(); // ok
v = std::move(*m4.begin()); // compile-time error
}
问题:
如果
b
为真,则v = *m4.begin();
应该没问题。
问题:
为什么
std::is_move_assignable
的行为不符合预期?
错误消息:( Clang 3.8 + Visual Studio 2015 Update 3)
error : cannot assign to non-static data member 'first' with const-qualified type 'const int' first = _Right.first; ~~~~~ ^ main.cpp(119,5) : note: in instantiation of member function 'std::pair<const int, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::operator=' requested here v = *m4.begin(); // error
答案 0 :(得分:5)
如果
b
为真,则v = *m4.begin();
应该没问题。
v = *m4.begin();
是复制分配,而不是移动分配。移动作业为v = std::move(*m4.begin());
。
但是作为T.C.指出并且Yam Marcovic也回答了,你使用std::is_move_assignable
是错误的,因为decltype(*m.begin())
是一个引用类型。您最终没有完全检查移动可分配性,并且您的支票 最终适用于v = *m4.begin();
。
对于移动分配,检查应为std::is_move_assignable_v<std::remove_reference_t<decltype(*m.begin())>>
。
无论如何,is_move_assignable
并不会太难以检查类型是否可移动可分配,它只检查类型是否将自身报告为可分配移动。
鉴于
template <typename T>
struct S {
S &operator=(S &&) { T() = "Hello"; return *this; }
};
std::is_move_assignable<S<int>>::value
会报告true
,因为签名S<int> S::operator=(S<int> &&);
格式正确。试图实际调用它会触发错误,因为T()
无法分配,即使可能,也无法分配字符串。
在您的情况下,类型为std::pair<const int, std::string>
。请注意那里的const
。
std::pair<T1, T2>
目前始终声明operator=
,但如果无法分配T1
或T2
,则尝试实际使用它会产生错误。
类模板可以确保operator=
的有效签名只有在其实例化形式良好以避免此问题时才会被声明,并且正如TC std::pair
will do so in the future所指出的那样。
答案 1 :(得分:3)
首先,作为*begin()
returns an lvalue reference,您实际上是将左值引用传递给std::is_move_assignable
,然后通过std::is_assignable<T&, T&&>
实现。std::is_move_assignable<SomeType&>
。现在,注意那里的转发引用,它转换为左值引用。这意味着通过询问std::is_assignable<T&, T&>
您已经有效地询问#include <iostream>
#include <type_traits>
struct S {
S& operator=(const S&) = default;
S& operator=(S&&) = delete;
};
int main()
{
std::cout << std::is_move_assignable<S>::value; // 0
std::cout << std::is_move_assignable<S&>::value; // 1
}
- 即。复制分配。当然,这有点误导。
您可能需要测试此代码以查看我的观点:
*begin()
所有这一切,pair<const int, string>&
在这种情况下返回const int
,因此无论如何它都不会是任何类型的,因为你无法分配给pair
。但是,正如@hvd指出的那样,由于函数在HTTP-EQUIV="Refresh"
模板中以原理声明,因此类型特征不理解如果编译器将其生成为实际函数,则后者会遇到错误
答案 2 :(得分:0)
解除引用空容器的.begin()
迭代器是未定义的行为。