函数模板接受并返回不同的lambdas
我的函数GetThing
如下:
auto GetThing(size_t index, auto&& l1)
{
return l1;
}
auto GetThing(size_t index, auto&& l1, auto&&... rest)
{
if (index == 0)
return l1;
return GetThing(index - 1, rest...);
}
我希望它也能够处理不同的lambdas,同时能够处理其他类型(即非lambdas、非函数,如int
和...),如
std::cout << GetThing(1, 2, 3, 4); //works, return 3
std::cout << GetThing(1, [] {return 0; },
[] {return 1; }, [] {return 2; },
[] {return 3; } )(); //nope
但这里的问题是lambda是不同类型的,因此递归函数会演绎为不兼容的返回类型,所以我似乎不得不这样使用std::function
,但它很难看。
std::cout << GetThing(1, std::function{ [] {return 0; } }, std::function{ [] {return 1; } }, std::function{ [] {return 2; } }, std::function{ [] {return 3; } })();//works
解决此问题的任何可能方法,例如,如果存在重载的operator()
,则它会自动将类型强制为std::function
?
编辑:我知道无捕获的lambdas可以转换为函数指针,但如何在模板中没有std::decay
的情况下推导出它?因为我仍然希望将其他类型作为引用进行处理
EDIT2:我收到了一些使用std::variant
的答案,我在想,除了lambda,参数类型应该是相同的,例如。std::variant<int, int, int>
。可以向GetThing
添加重载,这样当std::variant
持有相同类型时,它将返回该类型的内容,否则(接收lambdas的情况)将返回std::function
解决方案
您可以将函数存储在变量数组中。当然,这也带来了一些开销。但这使函数也可以使用捕获的变量。
这使您能够从这样的函数集合中选择一个函数,并使用给定的参数执行它,如下所示:
template < typename ARR_T >
struct Collect
{
template < typename ... T >
Collect( T&&...args ): arr{std::forward<T>(args)...}{}
ARR_T arr;
using VARIANT_T = ARR_T::value_type;
VARIANT_T& operator[]( size_t index) { return arr[index]; }
};
template < typename ... T >
Collect( T&& ... args ) -> Collect< std::array< std::variant<T... >, sizeof...(T) >>;
template < typename C, typename ... PARMS >
auto GetThing( size_t index, C&& c, PARMS&&... parms )
{
return std::visit( [ &parms...]( auto&& func)
{
return func(std::forward<PARMS>(parms)...);
}, c[index]);
}
int main()
{
std::cout << GetThing( 2, Collect( []( int, double) {return 0; }, []( int, double) {return 1; }, []( int, double) {return 2; }, []( int, double) {return 3; }), 1,5.6)<< std::endl;
int y = 8;
double d = 9.99;
std::cout << GetThing( 0, Collect( [y,d]( int, double) {return d*y; }, []( int, double) {return 1.; }, []( int, double) {return 2.; }, []( int, double) {return 3.; }), 1,5.6)<< std::endl;
}
在本例中GetThing
还获取用于调用lambda的函数参数,因为调用使用std::visit
。如果您只想选择该函数(&Q;),您将获得std::variant
(如果您喜欢),并且可以自己调用该函数。
auto func = Collect( []( int i, double d) {return d+i; }, []( int i, double d) {return d*i; }, []( int i, double d) {return d-i; } )[2];
std::cout << std::visit( []( auto&& f) { return f( 9, 7.77 ); }, func ) << std::endl;
}
相关文章