2012-09-18 77 views
3

將此ScopeExit類關閉代碼項目,但它不會構建在GCC 4.5.3上。感謝任何幫助。通過ctor rvalue參數進行Lambda賦值

class ScopeExit : private boost::noncopyable 
{ 
    typedef std::function<void()> func_t; 

public: 
    ScopeExit(func_t&& f) : func(f) {} 
    ~ScopeExit() { func(); } 

private: 
    // no default ctor 
    ScopeExit(); 

    // Prohibit construction from lvalues. 
    ScopeExit(func_t&); 

    // Prohibit new/delete. 
    void* operator new(size_t); 
    void* operator new[](size_t); 
    void operator delete(void *); 
    void operator delete[](void *); 

    const func_t func; 
}; 


ScopeExit exit = [&]() { }; 

GCC 4.5.3錯誤:

In member function ‘void test()’: 
error: conversion from ‘test()::<lambda()>’ to non-scalar type ‘ScopeExit’ requested 

編輯:

ScopeExit exit([&]() { }); // this works 
+0

由於這是C++ 11代碼:爲什麼使用'private'構造函數/運算符來禁止這些?有什麼錯誤'ScopeExit(func_t&)= delete;'?另請注意,編譯器生成的默認構造函數是禁用的,因爲該類型具有用戶定義的構造函數,並且如果構造函數onyl接受rvalues,則從左值構造是不可能的,因此這兩個構造函數都不需要被徹底刪除。對於'operator new/delete'使用'= delete;'應該這樣做。 – Grizzly

+0

我沒有寫代碼。就像我說的,它來自代碼項目。 –

回答

3

它的複製/移動初始化。您的複製c-tor被刪除,移動c-tor也被刪除。

n3337 12.8/9

如果一個類X的定義不明確宣佈此舉的構造函數,一個將被隱式聲明 欠繳當且僅當

- X沒有一個用戶聲明的拷貝構造函數,

- X沒有一個用戶聲明的拷貝賦值運算符,

- X沒有一個用戶聲明的舉動賦值運算符,

- X沒有一個用戶聲明的析構函數,並

- 此舉構造不會被隱式定義爲刪除。

有沒有想法,爲什麼第一種情況是不行的,但這種情況下正常工作

template<typename T> 
ScopeExit(T&& f) : func(std::move(f)) {} 
ScopeExit(ScopeExit&& rhs) : func(std::move(rhs.func)) { }] 

編輯。

當我們使用類型變量copy-initialization時,只使用標準和elipsis隱式轉換。從lambda轉換爲函數指針或從函數指針到std::function的轉換爲user-defined conversion並未使用。

n3337 8.5/16

初始值設定項的語義如下。目標類型是初始化的對象或引用類型 ,源類型是初始值設定項表達式的類型。如果初始化程序不是單個(可能爲 括號)表達式,則不定義源類型。

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

否則(即,對於剩餘的複製的初始化情況),即可以從源類型轉換爲用戶定義的轉換序列 目的地類型或(當使用轉換功能 時)到它的派生類如13.3.1.4所述被枚舉,並且最好的是通過重載決議(13.3)選擇的 。如果轉換無法完成或模糊不清,則初始化格式不正確。

n3337 13.3.1.4/1

下在8.5所規定的條件,如類類型的對象的副本初始化的一部分,用戶定義的 轉換可以被調用來轉換一個初始化表達式被初始化的對象的類型。 重載解析用於選擇要調用的用戶定義的轉換。假定「cv1 T」是 被初始化的對象的類型,其中T是類類型,候選函數的選擇如下:

- T的轉換構造函數(12.3.1)是候選函數。

  1. 在這兩種情況下,參數列表都有一個參數,它是初始化表達式。 [注意:此參數 將與構造函數的第一個參數以及轉換函數的隱式對象參數 進行比較。 - 注完]

n3337 13.3.2

1.從一組給定上下文(13.3.1)中,一組可行函數構建候選函數是 選擇,從通過比較 最佳擬合(13.3.3)的參數轉換序列來選擇最佳函數。可選功能的選擇考慮參數和功能之間的關係,而不是轉換序列的排名。

其次,對於F至是一個可行的功能,須爲每個參數存在的隱式轉換SE- quence(13.3.3.1),該該參數轉換爲F.

的相應參數n3337 13.3.3.1/4

但是,在第13步的第2步中爲複製/移動臨時對象調用時,13.3.1.3考慮構造函數或用戶定義的轉換函數的參數時,該參數爲 類 複製初始化,按13.3.1.7時通過初始化器列表作爲單個參數,或者當初始化器列表恰好具有一個元素並且轉換爲某個類別X或對(可能是cv-qualified)X的引用時, 被考慮用於X的構造器的第一個參數,或者13.3.1.4,13.3.1.5或13.3.1.6,在所有情況下,只考慮 標準轉換序列和省略號轉換序列。

+1

第一個案例因Matt在另一個答案中所說的而不起作用,不是嗎?如果沒有複製構造函數可用,則複製初始化將不起作用。 – jogojapan

+0

奇怪的代碼如何在MSVC2010上編譯。最有可能的MC++編譯器錯誤。 –

+1

@jogojapan如果有'用戶聲明的移動C-tor' - 代碼將不起作用。有相同的錯誤。所以,如果你使用'ScopeExit exit = ScopeExit([](){});'會正常工作。 – ForEveR

1

通過將複製構造函數設爲私有,您已禁止複製初始化(這是第一種情況發生的情況)。但是您的構造函數ScopeExit(func_t&& f) : func(f) {}是公開的,這就是第二個(工作)聲明中調用的內容。玩弄兩個計算機的訪問控制規範應該驗證這一點。

編輯:錯誤的術語如永遠指出,effectively-- ScopeExit(func_t&& f) : func(f) {}不是移動構造函數。但這就是第二種情況所要求的,這就是爲什麼它起作用,而copy-ctor的隱私是第一種情況沒有的原因。

+0

複製ctor沒有const缺少? – ltjax

+0

@Itjax很好的電話,我沒有想到,但看到[這裏](http://www.cplusplus.com/articles/y8hv0pDG/),任何版本都可以工作(並且禁用默認的ctor)。 –

+0

其「移動C-tor」不公開。它不是'user-defined',我們有'用戶定義的複製c-tor',所以它不能被聲明爲默認。 C-tor,接收其他類型的參數,該類不是「移動C-tor」。 – ForEveR