2014-09-24 71 views
27

考慮這個C++代碼11:C++ 11是否需要將此lambda聲明爲mutable?

#include <functional> 
#include <cstdlib> 

template <typename F> 
void test(F &&f) { 
    auto foo = [f]() { 
     f(); 
    }; 
    foo(); 
} 

int main() { 
    test(std::bind(std::puts, "hello")); 
    return 0; 
} 

GCC和鏘接受這個作爲有效的C++代碼11,但Visual Studio的2013需要lambda來聲明可變(auto foo = [f]() mutable { ... })。否則我得到這個錯誤:

error C3848: expression having type ' const std::_Bind<true,int,int (__cdecl *const)(const char *),const char (&)[6]> ' would lose some const-volatile qualifiers in order to call ' int std::_Bind<true,int,int (__cdecl *const)(const char *),const char (&)[6]>::operator()<>(void) '

是Visual Studio的權利拒絕這個代碼沒有可變的,或者它是有效的C + + 11?

回答

14

這是不是真正的lambda表達式;

(我敢肯定這是一個錯誤奇怪鏘如果你改變std::bind(std::puts, "hello")std::bind(std::exit, 0)顯然是因爲它認爲noreturn,使功能類型不同的拒絕代碼) 。

#include <functional> 
#include <cstdlib> 

int main() { 
    const auto x = std::bind(std::puts, "hello"); 
    x(); 
} 

這被GCC接受,但被MSVC拒絕。

標準不明確這是否有效,國際海事組織。 std::bind的返回值g有一個未指定的返回類型,其中g(...)有效且根據g的cv限定符定義,但該標準實際上沒有說明必須爲const限定的對象或引用調用任何operator()。它強烈暗示這是有效的,否則對g的cv限定符的引用似乎沒有用處,但實際上並不表示它是有效的。因此,我認爲MSVC的行爲不是標準的作者所期望的,但它可能符合標準的要求。

+0

不,它不符合標準。 「v(v1,v2,...,vN,result_of :: type)'「表示如果綁定的函數對象是'bind'的結果必須是可調用的。函數指針可以調用,不管它是否是'const',所以'bind'也必須是。 – 2014-09-24 13:16:15

+0

@MikeSeymour'g'是'std :: bind'的返回值,並且只有'g(...)'的行爲被指定。標準要求通過對該返回值的「const」限定引用來支持調用? – hvd 2014-09-24 13:22:13

+0

在上面給出的引用(20.8.9.1.2/3)中,加上以下子句「其中'cv'表示'g''的cv-qualifiers。調用'g'與調用'fd'(綁定的函數對象)具有相同的效果,將'g'的cv-限定符應用於'fd';因此,如果調用const FD,則對'g'的const限定副本/引用的調用必須是有效的。這裏,'FD'是一個函數指針類型,無論它是否是'const'都可以調用。 – 2014-09-24 13:27:50

10

這看起來像是在bind的Visual Studio實現中的一個錯誤,它只返回一個只有非const函數調用操作符的類型。它應該返回一個將所有函數調用轉發給綁定函數對象的類型,而不管它自己的cv資格如何。

總結C++ 11 20.8.9.1.2相當不透明的語言,bind的結果函數調用應該被轉發給綁定的函數對象,所以如果允許對那個對象的調用應該被允許。所以如果被綁定的函數對象不可調用,那麼這將是一個錯誤,如果const;但是在這裏,作爲一個函數指針,它可以被調用而不管cv資格如何。

相關問題