[英]Can I force a default special member function to be noexcept?
由於我已將移動賦值運算符聲明為noexcept
因此以下結構無法在C ++ 11下編譯:
struct foo
{
std::vector<int> data;
foo& operator=(foo&&) noexcept = default;
};
編譯器生成的默認移動賦值運算符是noexcept(false)
因為std::vector<int>
的移動賦值也是noexcept(false)
。 這反過來是由於默認分配器將std::allocator_traits<T>:: propagate_on_container_move_assignment
設置為std::false_type
。 另見這個問題 。
我相信這已在C ++ 14中修復 (參見庫缺陷2103 )。
我的問題是,有沒有辦法讓我在默認移動賦值賦值運算符上強制noexcept
而不必自己定義它?
如果這是不可能的,有沒有辦法可以將std::vector<int>
欺騙為noexcept
move assignable,以便將noexcept(true)
傳遞給我的struct?
我相信這已在C ++ 14中修復(參見庫缺陷2103)。
作為修復的DR應該被認為是對C ++ 11的修正,因此一些C ++ 11實現已經修復了它。
我的問題是,有沒有辦法讓我在默認移動賦值賦值運算符上強制
noexcept
而不必自己定義它?
對於默認的移動賦值運算符是noexcept
您需要使其子對象具有noexcept
移動賦值運算符。
我能想到的最明顯的可移植方式是使用std::vector
周圍的包裝器來強制移動為noexcept
template<typename T, typename A = std::allocator<T>>
struct Vector : std::vector<T, A>
{
using vector::vector;
Vector& operator=(Vector&& v) noexcept
{
static_cast<std::vector<T,A>&>(*this) = std::move(v);
return *this;
}
Vector& operator=(const Vector&) = default;
};
另一個類似的選項是使用DR 2013修復定義您自己的分配器類型並使用:
template<typename T>
struct Allocator : std::allocator<T>
{
Allocator() = default;
template<typename U> Allocator(const Allocator<U>&) { }
using propagate_on_container_move_assignment = true_type;
template<typename U> struct rebind { using other = Allocator<U>; };
};
template<typename T>
using Vector = std::vector<T, Allocator<T>>;
另一種選擇是使用標准庫實現,例如GCC,它實現DR 2013的解析,並且當已知所有分配器實例比較相等時,還使std::vector
的移動賦值運算符noexcept
用於其他分配器類型。
我不認為你可以強迫任何東西,但你可以包裝它:
#include <iostream>
#include <vector>
template <typename T>
struct Wrap
{
public:
Wrap() noexcept
{
new (m_value) T;
}
Wrap(const Wrap& other) noexcept
{
new (m_value) T(std::move(other.value()));
}
Wrap(Wrap&& other) noexcept
{
std::swap(value(), other.value());
}
Wrap(const T& other) noexcept
{
new (m_value) T(std::move(other));
}
Wrap(T&& other) noexcept
{
new (m_value) T(std::move(other));
}
~Wrap() noexcept
{
value().~T();
}
Wrap& operator = (const Wrap& other) noexcept
{
value() = other.value();
return *this;
}
Wrap& operator = (Wrap&& other) noexcept
{
value() = std::move(other.value());
return *this;
}
Wrap& operator = (const T& other) noexcept
{
value() = other;
return *this;
}
Wrap& operator = (T&& other) noexcept
{
value() = std::move(other);
return *this;
}
T& value() noexcept { return *reinterpret_cast<T*>(m_value); }
const T& value() const noexcept { return *reinterpret_cast<const T*>(m_value); }
operator T& () noexcept { return value(); }
operator const T& () const noexcept { return value(); }
private:
typename std::aligned_storage <sizeof(T), std::alignment_of<T>::value>::type m_value[1];
};
struct Foo
{
public:
Foo& operator = (Foo&&) noexcept = default;
std::vector<int>& data() noexcept { return m_data; }
const std::vector<int>& data() const noexcept { return m_data; }
private:
Wrap<std::vector<int>> m_data;
};
int main() {
Foo foo;
foo.data().push_back(1);
Foo boo;
boo = std::move(foo);
// 01
std::cout << foo.data().size() << boo.data().size() << std::endl;
return 0;
}
(謝謝Jonathan Wakely)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.