C++ 将lambda传递到变量std::函数时的类型推断
我试图使用用于处理数组的函数的类型信息从数组的元组中检索值。但是,对于这种情况,类型推断失败(部分原因是?),因为需要为C++ 将lambda传递到变量std::函数时的类型推断,c++,templates,c++17,variadic-templates,std-function,C++,Templates,C++17,Variadic Templates,Std Function,我试图使用用于处理数组的函数的类型信息从数组的元组中检索值。但是,对于这种情况,类型推断失败(部分原因是?),因为需要为std::function的类型名使用标识结构。这里有恢复扣减的方法吗 #include <functional> #include <iostream> #include <tuple> class comp_a { public: static const size_t id = 0; int val = 0; };
std::function
的类型名使用标识结构。这里有恢复扣减的方法吗
#include <functional>
#include <iostream>
#include <tuple>
class comp_a
{
public:
static const size_t id = 0;
int val = 0;
};
class comp_b
{
public:
static const size_t id = 1;
int val = 0;
};
class comp_c
{
public:
static const size_t id = 2;
int val = 0;
};
template<size_t size, typename ... Cs>
struct storage
{
template<typename T> struct identity { using type = T; };
template<typename ... Ts>
void get(size_t index, typename identity<std::function<void(Ts& ...)>>::type f)
{
f(std::get<Ts::id>(components)[index] ...);
}
std::tuple<std::array<Cs, size> ...> components;
};
int32_t main()
{
storage<20, comp_a, comp_b, comp_c> storage;
storage.get(2, [](comp_a& a, comp_c& c) { // Doesn't work
// storage.get<comp_a, comp_c>(2, [](comp_a& a, comp_c& c) { // Works
std::cout << a.val << " " << c.val << std::endl;
});
}
#包括
#包括
#包括
a类公司
{
公众:
静态常量大小\u t id=0;
int-val=0;
};
b类化合物
{
公众:
静态常量大小\u t id=1;
int-val=0;
};
c类化合物
{
公众:
静态常量大小\u t id=2;
int-val=0;
};
模板
结构存储
{
模板结构标识{using type=T;};
模板
void get(大小索引,类型名称标识::类型f)
{
f(std::get(components)[索引]…);
}
std::元组组件;
};
int32_t main()
{
储存;
storage.get(2,[](comp_a&a,comp_c&c){//不工作
//获取(2,[](comp_a&a,comp_c&c){//Works
std::cout我不确定标识
结构是用于什么,但是删除它会给出更清晰的错误消息(模板推断失败)
编译器无法从lambda派生std::function
类型。为证明这一点,编译了以下代码:
storage.get(2, std::function<void(comp_a& a, comp_c& c)>([](comp_a& a, comp_c& c) { // Doesn't work
std::cout << a.val << " " << c.val << std::endl;
}));
storage.get(2,std::function([](comp_a&a,comp_c&c){//不工作
std::cout;
};
}
模板
结构存储
{
模板
void get(大小索引,类型名称std::函数f)
{
f(std::get(components)[索引]…);
}
模板
void get(大小索引,λl)
{
get(索引,typename细节::推断类型::类型(l));
}
std::元组组件;
};
您标记了C++17,因此可以使用std::function
的演绎指南
因此,正如Alan Birtles所建议的,您可以将lambda作为简单类型接收,将其转换为std::function
(演绎指南)并推断参数的类型
像
template<size_t size, typename ... Cs>
struct storage
{
template<typename ... Ts>
void get(size_t index, std::function<void(Ts& ...)> f)
{ f(std::get<Ts::id>(components)[index] ...); }
template <typename F>
void get(size_t index, F f)
{ get(index, std::function{f}); }
std::tuple<std::array<Cs, size> ...> components;
};
模板
结构存储
{
模板
void get(大小索引,标准::函数f)
{f(std::get(components)[index]…);}
模板
void get(大小索引,F)
{get(index,std::function{f});}
std::元组组件;
};
您可以使用std::function
推断向导技巧来提取参数,但您确实不想实际创建std::function
。您想在lambda区域进行堆栈。std::function
由于类型擦除而增加开销和分配-但您所做的任何事情实际上都不需要类型擦除提供的好处。这是一种全损而无赢。实际上并不会产生std::function
也就是说,您当然仍然需要参数。因此您可以这样做:
template <typename T> struct type { };
template <typename F>
void get(size_t index, F f) {
using function_type = decltype(std::function(f));
get_impl(index, f, type<function_type>{});
}
您需要uncvref\t
来处理Args
可能是或可能不是合格的参考或cv的情况
现在,这对任何可调用的函数都不起作用。如果你传入一个通用lambda,那么推断std::function
将失败。但是……无论如何,这都不起作用,所以这似乎不是一个很大的损失?我对你的具体问题没有答案,但是为什么要使用std::function
呢?你不能使用id吗entity::type
(甚至void(Ts&…)
?遗憾的是,常规函数指针不起作用,因为它排除了lambda内部的任何捕获(这是我想做的,尽管在本例中我没有做)。当我尝试它时,它似乎也失败了参数推断。通过标识运行它会出现相同的问题,即推断对函数参数是盲目的。标识类型的一次使用正是您试图避免的。它使您的参数不可推断,因此必须在模板类型列表中指定它。因此我不确定为什么我要这样做在那里…甚至是std::remove\u cv\u t::id
@Jarod42-ehmmm…为什么?我的意思是:没有它会出什么问题?处理std::function
。你介意向我解释一下type
在这里起什么作用以及为什么有必要吗?@rtek我们需要std::function
的类型来推断参数,但我们不需要“我不想创建那种类型的对象。type
只是传递类型的一种方式。”
template<size_t size, typename ... Cs>
struct storage
{
template<typename ... Ts>
void get(size_t index, std::function<void(Ts& ...)> f)
{ f(std::get<Ts::id>(components)[index] ...); }
template <typename F>
void get(size_t index, F f)
{ get(index, std::function{f}); }
std::tuple<std::array<Cs, size> ...> components;
};
template <typename T> struct type { };
template <typename F>
void get(size_t index, F f) {
using function_type = decltype(std::function(f));
get_impl(index, f, type<function_type>{});
}
template <typename T> using uncvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
template <typename F, typename R, typename... Args>
void get_impl(size_t index, F f, type_t<std::function<R(Args...)>>) {
f(std::get<uncvref_t<Args>::id>(components)[index] ...);
}