但爲什麼會結合這樣的方式設計,這編譯:
auto g = std::bind(&Foo::baz, &foo);
我可以叫f
,但我永遠不能叫g
。爲什麼要編譯?
的Boost.Bind FAQ說Boost.Bind通常會在診斷「綁定時間」這樣的錯誤(即你在哪裏打電話bind
行)。然而,標準並沒有要求對std::bind
,而不是它在以下需要std::bind
元件:
INVOKE (fd, w1, w2, ..., wN)
(20.9.2)應爲某些值W1有效的表達式,W2, ...,wN,其中N == sizeof...(bound_args)
。
這意味着你的代碼違反了函數的前提條件,這會導致未定義的行爲。標準庫的實現沒有義務檢查違反先決條件,這是你的工作。這個庫也不禁止檢查它們,所以它會符合一個實現來拒絕它,就像Boost.Bind一樣。我會向圖書館供應商提出請求,要求他們在可能的情況下診斷無效的綁定表達式,作爲「實施質量」增強功能。
爲什麼不只是默認通所有按照正確的順序的參數,而不必指定呢?
我能想到兩個原因。
首先,通過bind
創建的調用包裝的行爲是丟棄不對應於一個佔位符參數,所以你可以調用x(1, 2, 3)
並讓它忽略所有的參數,並調用foo.bar()
。這是一種通用模式的一部分,您可以使用bind
來包裝一個N-arity函數,以創建一個完全不同的元素的調用包裝器,該元素可能會添加參數,刪除它們,修復某些特定的綁定值等。如果在綁定表達式中未使用佔位符時的默認行爲是轉發所有參數,則不可能使所有參數都被刪除。
其次,總是要求你明確哪些參數要以哪個順序傳遞,這更加一致。一般來說,只有在沒有綁定參數的情況下傳遞所有調用參數纔有意義,否則bind
應該如何知道是否在綁定參數之前或之後傳遞調用參數?
例如鑑於
struct X {
void f(int, int) { }
} x;
auto h = bind(&X::f, &x, 1);
h(2);
應x.f(1, 2)
或x.f(2, 1)
調用h(2)
結果呢?由於當存在綁定參數時的正確行爲並不明顯,所以當沒有佔位符時,自動轉發所有參數只有在沒有綁定參數時纔有意義(因爲不存在綁定參數應該先出現還是後出現的問題) ,這是一個相當特殊的情況。改變API的一個重要特性來處理這種特殊情況將具有可疑價值,尤其是當它使得不可能實現的情況下。
另一種解決方案是繼續要求用戶明確他們想要的內容,但提供一個明確的方式來表達TomaszKamiński在N4171中提出的「只轉發所有內容」,這將在接下來的C++委員會會議上討論周。該_all
佔位解決決定調用參數是否應該來綁定參數之前或之後,因爲你可以明確地說,你是否想問題bind(f, arg1, arg2, std::placeholders::_all)
或bind(f, std::placeholders::_all, arg1, arg2)
甚至bind(f, arg1, std::placeholders::_all, arg2)
大概是因爲沒有辦法得到的參數個數這意味着生成的函數對象必須允許*任意數量的參數,包括none,如果(例如)'g'被「調用」而沒有參數,會導致未定義的行爲。 – 2014-10-10 11:36:11
我認爲'std :: placeholders'執行兩個函數,1.如你所說,它們將參數從源代碼傳遞到彙編代碼,2.它們表示需要多少個參數。 – Niall 2014-10-10 11:40:57
boost庫可能有更多與「bind」相關的原始設計原理。 – Niall 2014-10-10 11:41:51