2013-09-11 7 views
8

次の構造が原因私はnoexceptとして移動代入演算子を宣言しているという事実のためにC++ 11の下でコンパイルに失敗します。コンパイラによって生成されるデフォルトの移動代入演算子が原因事実にnoexcept(false)あるデフォルトの特別なメンバー関数をnoexceptにすることはできますか?

struct foo 
{ 
    std::vector<int> data; 
    foo& operator=(foo&&) noexcept = default; 
}; 

そのstd::vector<int>の移動割り当てはnoexcept(false)です。これは、デフォルトのアロケータがstd::allocator_traits<T>:: propagate_on_container_move_assignmentstd::false_typeに設定されているためです。 this questionも参照してください。

これはC++ 14で修正されていると思います(library defect 2103参照)。

私の質問は、自分で定義することなく、デフォルトの移動代入代入演算子にnoexceptを強制する方法がありますか?

これが可能でない場合はをnoexceptに割り当てることができますか?noexcept(true)が私の構造体に渡されるように割り当て可能ですか?

+2

が、それは大丈夫です::ベクトル ' 'A'はデフォルトの' std :: allocator 'ではありません? – aschepler

+1

私は、コードの複雑さを最小限に抑えるために探しています。私はカスタムアロケータを使用することは、他のコーダが単純な非デフォルト移動代入演算子よりも理解するのが難しいと予想しています。 – marack

+1

これは、 'std :: vector 'の 'A'がデフォルトのアロケータのための単純なインラインラッパーであれば、それは働くかもしれません... – marack

答えて

4

これはC++ 14で修正されていると思います(ライブラリの欠陥2103を参照)。

修正プログラムは、C++ 11の修正と見なされる必要があります。そのため、一部のC++ 11実装ではすでに修正されています。

私の質問は、noexceptをデフォルトの移動割り当て割り当て演算子に強制的に強制して、自分で定義する必要はありませんか?

デフォルトの移動代入演算子がnoexceptになるようにするには、そのサブオブジェクトにnoexcept移動代入演算子を割り当てる必要があります。

私は考えることができる最も明白なポータブルな方法は、別の同様のオプションがDR 2013の修正プログラムを使用して独自のアロケータのタイプを定義することです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; 
    }; 

する動きを強制std::vectorのラッパーを使用することで、それを使用します。

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>>; 

別のオプションは、DR 2013年までの解像度を実現し、またstd::vectorの移動代入演算子012を作るようにGCCのような標準のライブラリ実装を使用することですすべてのアロケータ・インスタンスが等しいかどうかがわかっている場合は、他のアロケータ・タイプの場合はとなります。

1

私はあなたが何かを強制することができるとは思わないが、あなたはそれをラップすることがあります。

#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; 
} 

`data`は` STDであれば(感謝ジョナサンWakely)

+1

そのタイプはコピーできません。コピーと割り当てが必要です。また、char配列の代わりに 'std :: aligned_storage :: type'を使用することもできます。 –

関連する問題