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我知道:)如果我想完全指定类型,是否有正确的方法是什么? –