2016-02-18 38 views
6

请考虑以下一组示例。是否有可能在lambda中捕获可变数量的参数?

  1. 函数takeOnlyVoidFunction接受一个带有零参数的函数并简单地执行它。
  2. 函数takeVariableArguments需要可变数量的参数并使用参数执行该函数。
  3. 函数captureVariableArgs尝试将第二个函数转换为第一个函数可接受的lambda表单,但它不能编译。

我怎样才能使函数captureVariableArgs编译,并表现出转换函数的参数个数可变成闭合不带参数的正确的行为?

#include <stdio.h> 
#include <functional> 

void takeOnlyVoidFunction(std::function<void()> task) { 
    task(); 
} 

template<typename _Callable, typename... _Args> 
    void takeVariableArguments(_Callable&& __f, _Args&&... __args) { 
    __f(__args...); 
} 

// How can I make this function compile? 
template<typename _Callable, typename... _Args> 
    void captureVariableArgs(_Callable&& __f, _Args&&... __args) { 
    takeOnlyVoidFunction([=]() { __f(__args...);}); 
} 

void normalFunction(int a, int b) { 
    printf("I am a normal function which takes params (%d,%d)\n", a, b); 
} 

int main() { 
    int a = 7; 
    int b = 8; 
    takeVariableArguments(normalFunction, a, b); 
    takeOnlyVoidFunction([=](){ normalFunction(a,b);}); 
    captureVariableArgs(normalFunction, a, b); 
} 

我跑gcc 4.9.2。这是我看到的编译器错误。

g++ -std=c++11 Test.cc -o Test 
Test.cc: In instantiation of ‘captureVariableArgs(_Callable&&, _Args&& ...)::<lambda()> [with _Callable = void (&)(int, int); _Args = {int&, int&}]’: 
Test.cc:16:38: required from ‘struct captureVariableArgs(_Callable&&, _Args&& ...) [with _Callable = void (&)(int, int); _Args = {int&, int&}]::<lambda()>’ 
Test.cc:16:50: required from ‘void captureVariableArgs(_Callable&&, _Args&& ...) [with _Callable = void (&)(int, int); _Args = {int&, int&}]’ 
Test.cc:28:45: required from here 
Test.cc:16:34: error: variable ‘__f’ has function type 
    takeOnlyVoidFunction([=]() { __f(__args...);}); 
           ^
Test.cc:16:34: error: variable ‘__f’ has function type 
Test.cc: In instantiation of ‘struct captureVariableArgs(_Callable&&, _Args&& ...) [with _Callable = void (&)(int, int); _Args = {int&, int&}]::<lambda()>’: 
Test.cc:16:50: required from ‘void captureVariableArgs(_Callable&&, _Args&& ...) [with _Callable = void (&)(int, int); _Args = {int&, int&}]’ 
Test.cc:28:45: required from here 
Test.cc:16:34: error: field ‘captureVariableArgs(_Callable&&, _Args&& ...) [with _Callable = void (&)(int, int); _Args = {int&, int&}]::<lambda()>::<__f capture>’ invalidly declared function type 
In file included from Test.cc:2:0: 
/usr/include/c++/4.9/functional:2418:7: error: ‘std::function<_Res(_ArgTypes ...)>::function(_Functor) [with _Functor = captureVariableArgs(_Callable&&, _Args&& ...) [with _Callable = void (&)(int, int); _Args = {int&, int&}]::<lambda()>; <template-parameter-2-2> = void; _Res = void; _ArgTypes = {}]’, declared using local type ‘captureVariableArgs(_Callable&&, _Args&& ...) [with _Callable = void (&)(int, int); _Args = {int&, int&}]::<lambda()>’, is used but never defined [-fpermissive] 
     function<_Res(_ArgTypes...)>:: 
    ^

更新:更小例子演示了这个问题。

#include <stdio.h> 

// How can I make this function compile? 
template<typename _Callable> 
void captureVariableArgs(_Callable&& __f) { 
    takeOnlyVoidFunction([=]{ __f(); }); 
} 

void normalFunction() { 
    printf("I am a normal function\n"); 
} 

int main(){ 
    captureVariableArgs(normalFunction); 
} 
+1

你的代码编译和工作,你看到什么问题? – ixSci

+0

带有注释的函数不会为我编译。你在叮当还是gcc? – merlin2011

+0

将在几分钟内更新并显示编译错误。 – merlin2011

回答

2

至于GCC另一个潜在的解决方法,而是采用了拉姆达,您可以使用std::bind

template <typename F, typename... Args> 
auto captureVariable(F&& f, Args&&... args) 
{ 
    return std::bind(std::forward<F>(f), std::forward<Args>(args)...); 
} 

这下GCC 4.9.3对我的作品。

+0

实际上,我确实也考虑过这个问题,它编译了它,但我不确定它是否相同。它在语义上是否相同? – merlin2011

+0

它在语义上与您的示例不完全相同,因为您在使用'[=]'时复制参数。这实际上应该转发他们。 – Yuushi

+0

@Yuushi,我相信'bind'会复制它的所有参数。它必须存储它们,所以它不能只转发它们。 – ixSci

2

在后的代码编译好了最新的铛& MSVC的编译器,但所有的GCCS拒绝编译。所以它似乎是一个gcc中的错误。不过,我发现了一个方法,使GCC幸福:就是不使用的可调用的参数的“通用参考”,像这样:

template<typename _Callable, typename... _Args> 
int captureVariableArgs(_Callable _f, _Args&&... _args) { 
    return takeOnlyVoidFunction([=]() { _f(_args...);}); 
} 

我无法解释为什么GCC不接受你的版本,虽然。我不熟悉gcc风格的错误报告,也无法从错误消息中提取真正的原因。但我认为解决方法是可以的,因为在这种情况下,我没有在“通用参考”中看到任何值。事实上,我不明白你为什么在参数上使用它。

+0

我使用通用引用,因为我正在实现一个线程库,而gcc中的std :: thread'实现为参数使用了一个通用引用,并且我猜测它对性能和灵活性是这样做的。 – merlin2011

+0

好吧,它由lambda用'[=]'复制。也许你可以在捕获列表中以某种方式移动它,从而只保留一个可移动类型的副本。 – PeterT

+0

@ merlin2011,在这个函数中它没有任何意义 - 只要将它复制到捕获列表 – ixSci

相关问题