如果您想使用非标准版本来创建仅基于rvalues有条件地
noexcept
的
move ctors
,并且带有您使用的值,则可以使用此版本:
namespace estd {
template<class T, class U = T, std::enable_if_t<
std::is_move_constructible<std::remove_reference_t<T>>::value &&
std::is_assignable<std::remove_reference_t<T>, std::remove_reference_t<U>&&>::value &&
!std::is_lvalue_reference<U>::value,
int> = 0
>
T rval_exchange(T& obj, U&& new_value) noexcept(
std::is_nothrow_move_constructible<std::remove_reference_t<T>>::value &&
std::is_nothrow_assignable<std::remove_reference_t<T>, std::remove_reference_t<U>&&>::value
)
{
T old_value {std::move(obj)};
obj = std::move(new_value);
return old_value;
}
}
如果您在obj
中使用左值引用作为要移动的值(即new_value
必须是绑定到右值的右值引用),或者使用不可移动构造的类型T,或者移动构造不能与该右值一起工作,则模板将被禁用。
这样,您可以定义noexcept move ctors。 此处演示。我之所以将函数限制为仅适用于rvalues,是因为通常情况下,复制并非noexcept
,尽管并非总是如此,并且因为在move ctors中应该使用exchange
,而使其不是noexcept
会使这些ctors不是noexcept
,这对于明显的原因不好。
void do_stuff() noexcept
{ }
class Sample
{
std::string mBody;
public:
Sample(const std::string& body = ""): mBody {body} {}
Sample(const Sample& s): mBody {s.mBody} {
printf("%s\n", __PRETTY_FUNCTION__);
}
Sample& operator=(const Sample& s) {
mBody = s.mBody;
printf("%s\n", __PRETTY_FUNCTION__);
return *this;
}
Sample(Sample&& dying) noexcept(
noexcept(do_stuff()) &&
noexcept(estd::rval_exchange(dying.mBody, {}))
):
mBody {estd::rval_exchange(dying.mBody, {})}
{
do_stuff();
printf("%s\n", __PRETTY_FUNCTION__);
}
Sample& operator=(Sample&& dying) noexcept(
noexcept(do_stuff()) &&
noexcept(estd::rval_exchange(dying.mBody, {}))
)
{
mBody = estd::rval_exchange(dying.mBody, {});
do_stuff();
printf("%s\n", __PRETTY_FUNCTION__);
return *this;
}
std::string body() const noexcept {return mBody;}
};
int main()
{
std::cout << std::boolalpha;
Sample rval{"wow such string very content"};
Sample dummy;
std::cout << noexcept( Sample(std::move(rval)) ) << std::endl;
std::cout << noexcept( dummy = std::move(rval) ) << std::endl;
Sample f (std::move(rval));
std::cout << rval.body() << std::endl;
std::cout << f.body() << std::endl;
std::cout << (estd::rval_exchange(f, std::move(rval))).body() << std::endl;
std::cout << f.body() << std::endl;
std::cout << "end" << std::endl;
}
T(T&&)
可能不是noexcept
。 - Jarod42