[英]Strange behavior with std::function
我正在使用C ++ 11庫中的標准函數包裝器,我看到它的布爾運算符有一些奇怪的行為。 如果我創建一個std::function
對象,則布爾運算符返回false。 如果我將nullptr
分配給對象並再次檢查,則仍然如此。 當我為它分配一個我已經轉換為函數指針的void指針時出現問題。 考慮以下程序:
#include <functional>
#include <iostream>
void* Test() {
return nullptr;
}
int main(int argc, char* argv[]) {
std::function<void()> foo;
std::cout << !!foo << std::endl;
foo = nullptr;
std::cout << !!foo << std::endl;
foo = reinterpret_cast<void(*)()>(Test());
std::cout << !!foo << std::endl;
return 0;
}
我期望輸出為0 0 0
但結果是0 0 1
(見演示 )。 任何人都可以解釋為什么布爾運算符在包含空的,不可調用的函數指針時返回true? 還請提一下在std::function
檢查nullptr
的解決方法
注意:我已經嘗試檢查目標是否為null(使用foo.target<void*>() == nullptr
)而不是使用布爾運算符,但似乎無論函數對象包含什么,目標始終為null(即使函數對象被調用完全正常)。
對我來說看起來像個錯誤。 首先,這是一個簡單的例子 ,不播放任何帶有強制轉換的游戲:
#include <functional>
#include <iostream>
typedef void (*VF)();
VF Test() {
return nullptr;
}
int main(int argc, char* argv[]) {
std::function<void()> foo(Test());
std::cout << !!foo << std::endl;
return 0;
}
它仍然用GCC打印1。 它不應該:
20.8.11.2.1
template<class F> function(F f);
template <class F, class A> function(allocator_arg_t, const A& a, F f);
7 要求:F
應為CopyConstructible
。 對於參數類型ArgTypes
,f
應為Callable
(20.8.11.2)並返回類型R
的拷貝構造函數和析構函數A
不拋出異常。
8 后置條件:!*this
如果滿足以下任何條件:
f
是一個NULL
函數指針。f
是指向成員的NULL
指針。F
是函數類模板的實例,並且!f
我不認為代碼正在做你認為它做的事情。 這一行:
foo = reinterpret_cast<void(*)()>(Test());
表示您從Test()
收到void*
。 然后,您繼續將此指針指向對象 reinterpret_cast
為指向函數的指針 。 這是不允許的,因此代碼會產生未定義的行為,因此編譯器的任何輸出都是有效的。
標准的相關部分是
5.2.10重新解釋強制轉換[expr.reinterpret.cast]
8有條件地支持將函數指針轉換為對象指針類型,反之亦然。 這種轉換的含義是實現定義的,除非實現支持兩個方向的轉換,將一種類型的prvalue轉換為另一種類型並返回,可能具有不同的cv-限定條件,將產生原始指針值。
9空指針值(4.10)將轉換為目標類型的空指針值。 [ 注意:
std::nullptr_t
類型的空指針常量不能轉換為指針類型,並且整數類型的空指針常量不一定轉換為空指針值。 - 結束說明 ]
和
4.10指針轉換[conv.ptr]
1 空指針常量是整數類型的整數常量表達式(5.19)prvalue,其計算結果為零或類型為
std::nullptr_t
。 空指針常量可以轉換為指針類型; 結果是該類型的空指針值 ,並且可以與對象指針或函數指針類型的每個其他值區分開 。
(強調我的)
這是一個簡化的測試用例,將std::function
(及其可能的錯誤)排除在等式之外:
#include <iostream>
int main() {
using fp_t = void(*)();
void* vn = nullptr;
fp_t foo = reinterpret_cast<fp_t>(vn); // GCC: warning, Clang: silence
//fp_t foo = reinterpret_cast<fp_t>(nullptr); // error (GCC and Clang!)
std::cout << !!foo << std::endl;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.