2014-08-31 83 views
3

這是我的代碼,我禁用了複製構造函數,但它也禁用了其他類型的隱式副本。在這種情況下任何工作?不允許複製構造函數,但允許從其他類型隱式複製

測試上:G ++(GCC)4.7.1

struct item { 
    int b; 
}; 

class test { 
public: 
    test(const test& copy) = delete; 

    test(const item& a) { 
    std::cout << "OK " << a.b << std::endl; 
    } 
}; 

int main() { 
    test a = item{10}; //error: use of deleted function ‘test::test(const test&)’ 
} 
+0

給'test'一招如果可以的話可以使用構造函數,或者如果不能使用直接初始化語法。 – 2014-08-31 07:07:18

+0

你使用哪個編譯器和版本? – 2014-08-31 07:08:20

+0

@IanCook:添加版本 – w00d 2014-08-31 07:08:59

回答

5

要麼給test一個移動構造函數:

test(test&&) = default; 

,或者使用直接初始化:

test a{item{10}}; 

沒有其他的解決方法。如果目標類型是類類型(例如test a = item{10};),則複製初始化通常需要可調用的副本或移動構造函數。


相關規則在第8.5節[dcl.init]/P17指定:

如果目標類型是(可能CV修飾)類類型:

  • 如果初始化是直接初始化,或者如果是複製初始化,其中源的cv非標準版本與目標的類別相同,或者目標的類別的派生類別被考慮。枚舉適用的構造函數 (13.3.1.3),最好的選擇是通過過載 分辨率(13.3)。調用如此選擇的構造函數以初始化 對象,初始化表達式或表達式列表作爲其參數 。如果沒有構造函數應用,或重載分辨率不明確,則初始化格式不正確。
  • 否則(即,對於剩餘的複製的初始化情況),用戶定義的轉換序列,其可以從源 類型轉換爲目標類型或(當使用的轉換函數) 派生類其被列舉如13.3.1.4, 中所述,最好的選擇是通過重載分辨率(13.3)。如果 轉換無法完成或不明確,則初始化爲 格式不正確。使用初始化程序 表達式作爲其參數調用所選函數;如果該函數是一個構造函數,則調用 將初始化 目標類型的cv不合格版本的臨時值。臨時是一個prvalue。調用 (這是構造函數的臨時情況)的結果然後用於根據上面的規則對 進行直接初始化,即 的對象是複製初始化的目標。在某些情況下,通過將中間結果直接構造 到被初始化的對象中,可允許實現消除該直接初始化中固有的複製;見12.2,12.8。

源的類型爲item,目的地類型爲test,它的拷貝初始化,所以它屬於第二個小點之下。只有一個使用test(const item& a)構造函數的可用轉換,所以test類型的臨時值是從item構造的,然後用於根據第一個項目符號點直接初始化目標。這又必須調用構造函數test,它可以接受const test &test &&參數。即使複製或移動消失,您仍然必須擁有這樣的構造函數。

+0

移動構造函數完成這項工作!謝謝 – w00d 2014-08-31 07:32:14

0

有三種選擇,我能想到的:

1)移動的構造
2)賦值運算符+默認的構造函數
3)調用構造明確

#include <iostream> 

struct item { 
    int b; 
}; 
struct test { 
    test(const test& copy) = delete; 
    test(const item& a) { 
     std::cout << "OK " << a.b << std::endl; 
    } 
// move: 
    test(test&& from) {} 
// added: 
    test() {} 
    test& operator = (const test& src) = default; 
}; 

int main() { 
//fine after move constructor: 
    test a = item{10}; 
//all fine with original 
    test b(item{20}); 
//fine after adding .ctor() and op= 
    test c; c = item{30}; 
} 
相關問題