C++ C++;将同构包装类型的元组转换为原始类型的元组

C++ C++;将同构包装类型的元组转换为原始类型的元组,c++,c++17,wrapper,variadic-templates,stdtuple,C++,C++17,Wrapper,Variadic Templates,Stdtuple,我想对函数调用std::apply();但是,我不能这样做,因为我使用的std::tuple当前已包装。例如: #include <tuple> template <class T> struct wrapped { wrapped(T t) : t(t) {} T t; }; template <class T, class ... Args> struct delay_call { T(*callback)(Args...);

我想对函数调用
std::apply()
;但是,我不能这样做,因为我使用的
std::tuple
当前已包装。例如:

#include <tuple>

template <class T>
struct wrapped
{
    wrapped(T t) : t(t) {}

    T t;
};

template <class T, class ... Args>
struct delay_call
{
    T(*callback)(Args...);
    std::tuple<Args...> params;

    delay_call(T(*callback)(Args...), Args ... params) :
        callback(callback), params(params...)
    {}

    T call()
    {
        return std::apply(callback, params);
    }
};

template <class T, class ... Args>
struct delay_call_with_wrap
{
    T(*callback)(Args...);
    std::tuple<wrapped<Args>...> w_params;

    delay_call_with_wrap(T(*callback)(Args...), wrapped<Args> ... w_params) :
        callback(callback), w_params(w_params...)
    {}

    T call()
    {
        std::tuple<Args...> params; // = w_params.t
        return std::apply(callback, actual_params);
    }
};

float saxpy(float a, float x, float y)
{
    return a * x + y;
}

int main()
{
    float a = 1, x = 2, y = 3;
    delay_call delay_saxpy(saxpy, a, x, y);

    wrapped w_a = 1.f, w_x = 2.f, w_y = 3.f;
    delay_call_with_wrap w_delay_saxpy(saxpy, w_a, w_x, w_y);

    float result = delay_saxpy.call();

    float w_result = w_delay_saxpy.call();
}
#包括
模板
结构包裹
{
包裹的(T):T(T){}
T;
};
模板
结构延迟调用
{
T(*回调)(参数…);
std::元组参数;
延迟调用(T(*回调)(参数…,参数…):
回调(回调),参数(参数…)
{}
T call()
{
返回标准::应用(回调,参数);
}
};
模板
带换行符的结构延迟调用
{
T(*回调)(参数…);
std::元组w_参数;
使用包装(T(*回调)(参数…,包装…w_参数)延迟包装调用:
回调(回调),w_参数(w_参数…)
{}
T call()
{
std::tuple params;//=w_params.t
return std::apply(回调,实际参数);
}
};
浮点saxpy(浮点a、浮点x、浮点y)
{
返回a*x+y;
}
int main()
{
浮点数a=1,x=2,y=3;
延迟\调用延迟\ saxpy(saxpy,a,x,y);
包裹的w_a=1.f,w_x=2.f,w_y=3.f;
使用wrap w w w u delay w u saxpy(saxpy,w w w u a,w w u x,w w w y)延迟调用;
float result=delay_saxpy.call();
float w_result=w_delay_saxpy.call();
}
延迟调用结构按预期工作;但是,我不确定如何提取每个元组元素的实际值,并将其交给
std::apply()
执行


简而言之,对于使用wrap::call的
delay\u call\u,我如何将
std::tuple
转换为
std::tuple

我将完全避免
std::apply
并通过使用
std::index\u序列解包元组直接调用
callback

template <std::size_t ...I> T call_low(std::index_sequence<I...>)
{
    return callback(std::get<I>(w_params).t...);
}

T call()
{
    return call_low(std::make_index_sequence<sizeof...(Args)>{});
}
template <class T, class ... Args>
struct delay_call_with_wrap
{
    T(*callback)(Args...);
    std::tuple<wrapped<Args>...> w_params;

    delay_call_with_wrap(T(*callback)(Args...), wrapped<Args> ... w_params) :
        callback(callback), w_params(w_params...)
    {}

    T call()
    {
        auto helper = [this] <class ... Args_> (wrapped<Args_>... args)
        {
            return callback(args.t...);
        };
        return std::apply(helper, w_params);
    }
};
模板T调用低(标准::索引序列)
{
返回回调(std::get(w_params).t.);
}
T call()
{
返回调用低(std::make_index_sequence{});
}

可能不是在实践中使用的最佳解决方案,但这里有一个使用可变模板lambda来避免
索引序列的解决方案

template <std::size_t ...I> T call_low(std::index_sequence<I...>)
{
    return callback(std::get<I>(w_params).t...);
}

T call()
{
    return call_low(std::make_index_sequence<sizeof...(Args)>{});
}
template <class T, class ... Args>
struct delay_call_with_wrap
{
    T(*callback)(Args...);
    std::tuple<wrapped<Args>...> w_params;

    delay_call_with_wrap(T(*callback)(Args...), wrapped<Args> ... w_params) :
        callback(callback), w_params(w_params...)
    {}

    T call()
    {
        auto helper = [this] <class ... Args_> (wrapped<Args_>... args)
        {
            return callback(args.t...);
        };
        return std::apply(helper, w_params);
    }
};
模板
带换行符的结构延迟调用
{
T(*回调)(参数…);
std::tuple
简言之,对于带有wrap::call的
delay\u call\u,如何将
std::tuple
转换为
std::tuple

在我看来,最好避免使用旧的
std::index_序列
/
std::index_序列
方式(参见HolyBlackCat答案)

但是,如果您真的想使用
std::apply()
,您可以第一次调用它来展开元组(以获得一个展开值的元组),然后像往常一样调用它

我的意思是

T call ()
 {
   auto actual_params = std::apply([](auto ... wt){ return std::make_tuple(wt.t...); },
      w_params);
   return std::apply(callback, actual_params);
}
或者,在一次通话中,直接

T call()
 {
   return std::apply(callback,
             std::apply([](auto ... wt){ return std::make_tuple(wt.t...); },
                w_params));
 }

这个解决方案是合理的,IMHO,如果
w_-param
成员是常量,那么您可以一次性计算
实际的w_-param
,并使其成为
静态的

欣赏std::apply的解决方案,即使旧的解决方案更合适。此外,w_-param对于我的用例来说不是常量因此,std::tuple类型的实际参数无法一次性计算。@MichaelChoi-我同意:最好的解决方案IMHO是HolyBlackCat的答案中的一个。我明白了……我没有意识到Lambda可以在C++17中模板化。我认为这个解决方案最容易实现。@MichaelChoi哦,对不起,我错过了C++17标记。模板化的lambdas只存在于C++20中(如图所示,还没有很好的编译器支持),但如果它们是语言中稳定的一部分,这将是一个很好的用例。