C++ lambda参数的模板推导

C++ lambda参数的模板推导,c++,C++,我目前有许多数据访问器,如: template <typename Fn> typename std::result_of<Fn(DataA)>::type GetDataA(Fn fn) { DataA a = DoSomeWorkToGetA(); return fn(a); } template <typename Fn> typename std::result_of<Fn(DataB)>::type GetDataB(Fn

我目前有许多数据访问器,如:

template <typename Fn>
typename std::result_of<Fn(DataA)>::type GetDataA(Fn fn) {
   DataA a = DoSomeWorkToGetA();
   return fn(a);
}

template <typename Fn>
typename std::result_of<Fn(DataB)>::type GetDataB(Fn fn) {
   DataB b = DoSomeWorkToGetB();
   return fn(b);
}
我想要的是一种自动生成这些getter组合的方法,如:

template <typename Fn>
typename std::result_of<Fn(DataA, DataB)>::type GetDataAandB(Fn fn) {
   DataA a = GetDataA([](DataA a) { return a; });
   DataB b = GetDataB([](DataB b) { return b; });
   return fn(a, b);
}
模板
typename std::result_of::type GetDataAandB(Fn-Fn){
dataaa=GetDataA([](dataaa){返回a;});
databb=GetDataB([](databb){return b;});
返回fn(a,b);
}
我在过去见过这样的事情,使用用户API,如:

auto computation_result_a = GetData<A>([](Data a) { /**/ });
auto computation_result_b = GetData<A>([](Data b) { /**/ });
auto computation_result_ab = GetData<A,B>([](Data a, Data b) { /**/ });
auto computing\u result\u a=GetData([](数据a){/**/});
自动计算结果=GetData([](数据b){/**/});
自动计算结果=GetData([](数据a,数据b){/**/});

但我不确定如何完成此操作。

首先,您需要类型(或标记)的映射来更正
DoSomeWorkToGet*
功能,例如:

template<typename T> /* or an enum instead of typename */
void DoSomeWorkToGet() = delete;

template<>
auto DoSomeWorkToGet<A>() { return DoSomeWorkToGetA(); }

template<>
auto DoSomeWorkToGet<B>() { return DoSomeWorkToGetB(); }

这需要C++17。使用C++11/C++14实现也是可能的,但a将需要稍多的工作(实现
std::apply
或更弱的形式)。它保证了求值顺序,因为列表初始化(在
tuple\u type{…}
中使用)始终严格按从左到右的顺序排列

@walnut Fair point。我已尽了最大努力加以阐述。谢谢你迫使我缩小问题的范围。好的,现在更有意义了。谢谢你的回复。这太棒了。调用Get()时,DoSomeWorkToGet()和DoSomeWorkToGetBack()的顺序是否有任何指定的行为?或者这是未指定的?@user13120497顺序不确定(因此任何顺序都可能发生,但没有交错)。如果您需要按顺序执行它们,则需要进行一些小的调整。是这样吗?@user13120497对不起,你是指评估顺序吗?或者您只是在讨论将哪个调用的结果分配给哪个函数参数的顺序?因为后者是定义良好的,只是从左到右通过参数。对不起-计算顺序。即,类似于此处
a
b
的未指定评估顺序:
foo(a(),b())
@user13120497查看我的第一条评论和对我答案的编辑,然后。
template<typename T> /* or an enum instead of typename */
void DoSomeWorkToGet() = delete;

template<>
auto DoSomeWorkToGet<A>() { return DoSomeWorkToGetA(); }

template<>
auto DoSomeWorkToGet<B>() { return DoSomeWorkToGetB(); }
template<typename... Ts, typename F> /* or an enum instead of the first typename */
auto GetData(F f) {
    return f(DoSomeWorkToGet<Ts>()...);
}
auto computation_result_ab = GetData<A, B>([](auto a, auto b) {
    return /* something with a and b */;
});
template<typename... Ts, typename F> /* or an enum instead of the first typename */
auto GetData(F f) {
    using tuple_type = std::tuple<decltype(DoSomeWorkToGet<Ts>())&&...>;
    return std::apply(f, tuple_type{DoSomeWorkToGet<Ts>()...});
}