Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/138.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 将lambda传递到变量std::函数时的类型推断_C++_Templates_C++17_Variadic Templates_Std Function - Fatal编程技术网

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] ...);
}