2017-01-30 34 views
3

據我瞭解[class.copy.ctor][class.copy.assign],在下面的代碼結構A不宜動,constructible也動彈不了,分配:不可能的隱式移動操作?

#include <type_traits> 


struct X { 
    X() noexcept; // user-declared default constructor 
    ~X() noexcept; // Force X not to be trivially copyable 
    X(X &&) = delete; // Explicitly deleted move constructor 
    X(X const &) = delete; // Explicitly deleted copy constructor 
    X & operator=(X &&) = delete; // Explicitly deleted move assignment operator 
    X & operator=(X const &) = delete; // Explicitly deleted copy assignment op. 
}; 
static_assert(!std::is_copy_constructible<X>::value, ""); 
static_assert(!std::is_copy_assignable<X>::value, ""); 
static_assert(!std::is_move_assignable<X>::value, ""); 
static_assert(!std::is_move_constructible<X>::value, ""); 
static_assert(!std::is_trivially_copyable<X>::value, ""); 
static_assert(!std::is_trivially_copy_assignable<X>::value, ""); 
static_assert(!std::is_trivially_copy_constructible<X>::value, ""); 
static_assert(!std::is_trivially_move_assignable<X>::value, ""); 
static_assert(!std::is_trivially_move_constructible<X>::value, ""); 


struct A { 
    A() noexcept; // user-declared default constructor 
    A(A const &) noexcept; // user-declared copy constructor 
    A & operator=(A const &) noexcept; // user-declared copy assignment operator 
    X x; 
}; 
static_assert(std::is_copy_constructible<A>::value, ""); 
static_assert(std::is_copy_assignable<A>::value, ""); 
static_assert(!std::is_move_assignable<A>::value, "");  // FAILS?! 
static_assert(!std::is_move_constructible<A>::value, "");  // FAILS?! 
static_assert(!std::is_trivially_copyable<A>::value, ""); 
static_assert(!std::is_trivially_copy_assignable<A>::value, ""); 
static_assert(!std::is_trivially_copy_constructible<A>::value, ""); 
static_assert(!std::is_trivially_move_assignable<A>::value, ""); 
static_assert(!std::is_trivially_move_constructible<A>::value, ""); 

但是,有兩個靜態斷言失敗,GCC和鐺,這意思是由於某種原因,A是可移動分配和移動可構建的。

在我的推理這應該不是,因爲struct A

  • 沒有顯式聲明的舉動構造
  • 沒有顯式聲明的舉動賦值運算符
  • 有一個用戶聲明的拷貝構造函數
  • 有一個用戶聲明的複製分配操作符。
  • 有一個x類型的X這是不能直接初始化與任何其他A::x,因爲所有參與重載決議的X的構造函數被明確刪除。

這是一個編譯器錯誤或我誤解的東西嗎?

回答

6

他們期望的行爲,因爲拷貝構造函數的存在和拷貝賦值運算符滿足MoveConstructible

類的要求沒有實現轉移構造,以滿足這類需求:拷貝構造函數這需要一個const T &參數可以綁定右值表達式。

MoveAssignable

的類型沒有實現移動賦值運算符爲了滿足這類需求:一個拷貝賦值運算符,通過價值需要它的參數或作爲一個const類型&,將綁定到右值的論點。

注意std::is_move_constructiblestd::is_move_assignable只是檢查指定的類型的對象可以被構造/從一個rvalue參數分配。即使沒有移動構造函數/賦值運算符,複製構造函數/賦值運算符也可以完成這項工作,因爲左值參數也可以傳遞給左值參考。

編輯

爲您展示了移動構造函數/賦值運算符的代碼示例說明不implcitly在所有申報(因爲用戶聲明的拷貝構造函數的存在和拷貝賦值運算符),所以他們贏了不會影響重載解析以及調用複製構造函數/賦值運算符的結果。但是,如果您明確聲明它們爲delete,則行爲將會因爲顯式刪除的函數參與重載解析而改變,並且它們將被優先選擇,然後std::is_move_constructiblestd::is_move_assignable將返回false

2

is_move_constructible/assignable不檢查是否存在移動構造函數或移動賦值操作符。它檢查是否可以從r值參考構造/分配類。在這種情況下,缺乏移動功能的類將使用複製構造函數/賦值運算符。

通常is_move_constructible/assignable弱於is_copy_constructible/assignable:以後在移動專用類型時失敗,前者通過檢查。

+1

@jotik你沒有從'A'中刪除它們。刪除和不生成是不同的東西:刪除的函數/構造函數參與重載解析,而不是生成的函數不。另外'x'成員默認初始化到處,因爲您沒有在用戶定義的構造函數中以其他方式告訴它。 –

相關問題