std::function
有一個固定的簽名。這是一個設計選擇,不是一個硬性要求。編寫支持多個簽名僞std::function
並不難:
template<class...Sigs>
struct functions;
template<>
struct functions<> {
functions()=default;
functions(functions const&)=default;
functions(functions&&)=default;
functions& operator=(functions const&)=default;
functions& operator=(functions&&)=default;
private:
struct never_t {private:never_t(){};};
public:
void operator()(never_t)const =delete;
template<class F,
std::enable_if_t<!std::is_same<std::decay_t<F>, functions>{}, int>* =nullptr
>
functions(F&&) {}
};
template<class S0, class...Sigs>
struct functions<S0, Sigs...>:
std::function<S0>,
functions<Sigs...>
{
functions()=default;
functions(functions const&)=default;
functions(functions&&)=default;
functions& operator=(functions const&)=default;
functions& operator=(functions&&)=default;
using std::function<S0>::operator();
using functions<Sigs...>::operator();
template<class F,
std::enable_if_t<!std::is_same<std::decay_t<F>, functions>{}, int>* =nullptr
>
functions(F&& f):
std::function<S0>(f),
functions<Sigs...>(std::forward<F>(f))
{}
};
使用:
auto f = [](int a = 3) {std::cout << a << std::endl; };
functions<void(int), void()> fs = f;
fs();
fs(3);
Live example。
這將爲每個過載創建一個單獨的lambda複製副本。甚至可以通過仔細鑄造針對不同的重載使用不同的lambda表達式。
你可以寫一個不這樣做,但它基本上需要重新實現std::function
與一個fancier內部狀態。
上述更高級的版本將避免使用線性繼承,因爲這將導致O(n^2)代碼和O(n)遞歸模板深度上的簽名數量。平衡二叉樹繼承將下降到生成的O(n lg n)代碼和O(lg n)深度。
工業強度版本將存儲一次傳入的lambda,使用小對象優化,手動僞vtable使用二進制繼承策略調度函數調用,並將調度函數指針存儲在所述僞代碼中,虛函數表。它將在每個類(而不是每個實例)基礎上使用O(#簽名)* sizeof(函數指針)空間,並且使用的每個實例的開銷與std::function
一樣多。
但是對於SO帖子來說這有點多,不是嗎?
start of it
'auto h = f;'? – MikeCAT
我不認爲'std :: function'有任何默認參數支持。 – chris
@MikeCAT我知道:)如果我想完全指定類型,是否有正確的方法是什麼? –