2012-12-01 148 views
1

我有一个相当特殊的问题,因为我试图建立某种形式的一个编译器... 我想lambda表达式传递给模板函数是这样的:将任意的lambda表达式传递给函数?

template<class T> 
delegate<T>* bind(std::function<T> func) 
{ 
    return nullptr; 
} 

所以,我现在可以请致电

bind([&](int a) { // do something }); 

...所以通常情况下,这不会是一个问题,因为std :: function能够捕获lambda。但是问题在于(让我们假设)我不知道或不想提供有关“T”究竟是什么的信息。它可以是任何函数签名,你也可以插入到std :: function <> ...

我还需要将此“推断”签名传回给我想返回的“委托”类,并且该委托类需要是一个指向class ...

现在我想出了这一点:

template<class T> 
struct delegate : public std::function<T> 
{ 
    delegate(const std::function<T>& func) : std::function<T>(func) { } 
    delegate(const delegate<T>& func) { } 
}; 

template<class T> 
delegate<T>* bind(std::function<T>&& func) 
{ 
    return new delegate<T>(std::forward<std::function<T>>(func)); 
} 

但一个电话“绑定”失败与上面的例子中“失败模板实参推演”。如何在不需要在调用“bind”时明确指定“T”参数的情况下工作(至少可以工作)?

由于理论上我的编译器有解决此问题的所有信息,我只需插入“T”的实例,但这会使生成的代码不必要地复杂化。

顺便说一句,我使用的是最新的Clang编译器。


下面是最终的解决方案:

template<typename T> struct get_signature; 
template<typename Mem, typename Ret, typename... Args> struct get_signature<Ret(Mem::*)(Args...) const> { 
    typedef Ret type(Args...); 
}; 

template<class T> 
delegate<typename get_signature<decltype(&T::operator())>::type>* bind(T func) 
{ 
    return nullptr; 
} 

请注意,您可能需要调整“常量”修饰您的需求。

+4

从std :: function继承是不明智的想法。我敢打赌,它没有虚拟析构函数。 – chris

+0

将'std :: function'作为参数传递出错了,但我不记得具体是什么。 –

+0

现在我们不用担心这些细节,我只是想让这个模板参数推演起作用!这只是一个展示这个想法的片段。可能是我现在混淆了它。我的意思是C++ 11的目的是要通过引用来传递,但我可以记住像shared_ptr和std :: function可能是一个例外。 – thesaint

回答

2

首先,你已经完全搞砸你的右值引用。您的转发根本不起作用。

其次,在某些情况下是不可能的。对于一些函数对象,你可以通过采取成员函数指针operator()和检查它的签名推断签名。但对于其他人来说,他们将会超载并且无法工作。

template<typename T> struct get_signature; 
template<typename Mem, typename Ret, typename... Args> 
struct get_signature<Ret(Mem::*)(Args...)> { 
    typedef Ret(Args...) type; 
}; 

template<class T> 
delegate<typename get_signature<&T::operator()>::type>* bind(T func) 
{ 
    return nullptr; 
} 

第三,std::bind

+0

你能否详细说明右值事情......因为我在上面完成的方式是我在教程^^中读到的。所以它很高兴知道最新的错误abotu它...我现在会尝试你的代码。 – thesaint

+0

你不会看到任何教程这样做。 T *必须是对象的类型* - 不是'std :: function '。 'std :: function &&'*总是*右值引用。而'std :: forward' *必须*带上'T' - 就像它一样,你总是将它作为右值转发。 – Puppy

+0

@thesaint对于完美的转发,推导出的类型必须是'T &&'形式。否则,它只是一个普通的旧的右值引用,而不是一个时髦的“通用引用”。 –

相关问题