【发布时间】:2016-04-21 07:41:08
【问题描述】:
最近,我在将作为参数传递的函数传递给 lambda 表达式时遇到了一个奇怪的问题。代码在 clang 3.5+ 中编译得很好,但在 g++ 5.3 中编译失败,我想知道问题出在 c++ 标准、clang 中的非标准扩展还是 GCC 中的无效语法解释。
示例代码非常简单:
template<typename Fn, typename... Args, typename T = typename std::result_of<Fn(Args...)>::type>
std::future<T>
async(Fn &&fn, Args &&... args)
{
std::shared_ptr<std::promise<T>> promise = std::make_shared<std::promise<T>>();
auto lambda = [promise, fn, args...](void)
{ promise->set_value(fn(std::move(args)...)); };
send_message(std::make_shared<post_call>(lambda));
return promise->get_future();
};
GCC 报告了以下内容:
error: variable ‘fn’ has function type
{ promise->set_value(fn(std::move(args)...)); };
(...)
error: field ‘async(Fn&&, Args&& ...) [with Fn = int (&)(int, int); Args = {int&, int&}; T = int]::<lambda()>::<fn capture>’ invalidly declared function type
auto lambda = [promise, fn, args...](void)
还好我找到了一个简单的变通方法,添加一个std::function对象,封装函数参数:
template<typename Fn, typename... Args, typename T = typename std::result_of<Fn(Args...)>::type>
std::future<T>
async(Fn &&fn, Args &&... args)
{
std::shared_ptr<std::promise<T>> promise = std::make_shared<std::promise<T>>();
std::function<T(typename std::remove_reference<Args>::type...)> floc = fn;
auto lambda = [promise, floc, args...](void)
{ promise->set_value(floc(std::move(args)...)); };
send_message(std::make_shared<post_call>(lambda));
return promise->get_future();
};
虽然我不完全理解第一段代码有什么问题,但它成功地用 clang 编译并运行没有错误。
编辑
我刚刚注意到,如果其中一个参数应该是参考,我的解决方案将灾难性地失败。因此,如果您有任何其他可能适用于 C++11 的建议(即没有专门的 lambda 捕获 [c++14 功能]),那将是非常酷的...
【问题讨论】:
-
如果将
auto p_fn = &fn传递给 lambda 会发生什么? -
@JoelCornett sigsegv 或类似的东西。传递
fn作为参考也发生了同样的事情。虽然它在这两种情况下都能编译。 -
@JoelCornett 在并发/异步环境中,将指针传递给作用域变量绝不是一个好主意。
标签: c++ c++11 gcc clang clang++