C++ 如何打开参数包包装?

C++ 如何打开参数包包装?,c++,templates,variadic-templates,compile-time,C++,Templates,Variadic Templates,Compile Time,我想在编译时使用std::ratio类型进行计算。我已经编写了一个处理参数包的基本函数。但是,为了在其他对象中保存比率,我将其放入参数包包装器中。如何打开包装好的参数包,将其放入函数中 我的代码如下: #include <ratio> #include <functional> #include <initializer_list> namespace cx { // I need constexpr accumulate. // Howev

我想在编译时使用
std::ratio
类型进行计算。我已经编写了一个处理参数包的基本函数。但是,为了在其他对象中保存
比率
,我将其放入参数包包装器中。如何打开包装好的参数包,将其放入函数中

我的代码如下:

#include <ratio>
#include <functional>
#include <initializer_list>

namespace cx {
    // I need constexpr accumulate.
    // However, the standard library currently doesn't provide it.
    // I therefore just copied the code from
    // https://en.cppreference.com/w/cpp/algorithm/accumulate
    // and added the constexpr keyword.
    template<class InputIt, class T, class BinaryOperation>
    constexpr T accumulate(InputIt first, InputIt last, T init, BinaryOperation op)
    {
        for (; first != last; ++first) {
            init = op(std::move(init), *first); // std::move since C++20
        }
        return init;
    }
}

// wrapper type
template <class...T> struct wrapper { };

// helper to get the value out of the ratio type        
template <class T>
struct get_val {
    static constexpr auto value = double(T::num) / double(T::den);
};

// function for calculating the product of a vector type
template <class T>
constexpr auto product(T values) {
    return cx::accumulate(std::begin(values),
                          std::end(values),
                          1,
                          std::multiplies<typename T::value_type>());
}

// my calculation (needs a parameter pack, can't the handle wrapper type)
template <class...T>
struct ratio_product
{
    // this works by wrapping the Ts into an initializer list
    // and using that for the calculation
    static constexpr auto value =
        product(std::initializer_list<double>{get_val<T>::value...});
};

//test
int main() {
    //this works on a parameter pack (compiles)
    static_assert(ratio_product<
        std::ratio<5>, std::ratio<5>, std::ratio<4>
    >::value == 100,"");

    //this should work on a parameter pack wrapper (does not compile)
    static_assert(ratio_product<
        wrapper<
            std::ratio<5>, std::ratio<5>, std::ratio<4>
        >
    >::value == 100,"");
}
#包括
#包括
#包括
命名空间cx{
//我需要constexpr。
//但是,标准库目前没有提供它。
//因此,我只是从中复制了代码
// https://en.cppreference.com/w/cpp/algorithm/accumulate
//并添加了constexpr关键字。
模板
constexpr T accumulate(先输入后输入、先输入后输入、先输入后输入、二进制操作op)
{
for(;first!=last;++first){
init=op(std::move(init),*first);//std::move自C++20
}
返回init;
}
}
//包装类型
模板结构包装{};
//帮助器从比率类型中获取值
模板
结构获取值{
静态constexpr auto value=double(T::num)/double(T::den);
};
//用于计算向量类型乘积的函数
模板
constexpr汽车产品(T值){
返回cx::累计(标准::开始(值),
标准::结束(值),
1.
std::multiples());
}
//我的计算(需要参数包,无法处理包装器类型)
模板
结构比乘积
{
//其工作原理是将Ts包装到初始值设定项列表中
//然后用它来计算
静态constexpr自动值=
产品(std::initializer\u list{get\u val::value…});
};
//试验
int main(){
//这适用于参数包(编译)
静态断言(比率乘积)<
标准比率,标准比率,标准比率
>::值==100,“”;
//这应该适用于参数包包装器(不编译)
静态断言(比率乘积)<
包装纸<
标准比率,标准比率,标准比率
>
>::值==100,“”;
}

我找到了解决方案。通过使用模板专门化,可以从包装器中提取参数包:

template <class...T> struct ratio_product {
    static constexpr auto value = product(std::initializer_list<double>{get_val<T>::value...});
};
template <class...T> struct ratio_product<wrapper<T...>> {
    static constexpr auto value = ratio_product<T...>::value;
};
模板结构比率\u产品{
静态constexpr auto value=product(std::initializer\u list{get\u val::value…});
};
模板结构比率\u乘积{
静态constexpr auto value=比率×乘积::值;
};

我找到了解决方案。通过使用模板专门化,可以从包装器中提取参数包:

template <class...T> struct ratio_product {
    static constexpr auto value = product(std::initializer_list<double>{get_val<T>::value...});
};
template <class...T> struct ratio_product<wrapper<T...>> {
    static constexpr auto value = ratio_product<T...>::value;
};
模板结构比率\u产品{
静态constexpr auto value=product(std::initializer\u list{get\u val::value…});
};
模板结构比率\u乘积{
静态constexpr auto value=比率×乘积::值;
};

以下是一种可重复使用的方法,可以将参数包展开到任意模板中:

template <class Wrapper, template <class...> class Template>
struct unwrap;

template <class... Ts, template <class...> class Template>
struct unwrap<wrapper<Ts...>, Template> {
    using type = Template<Ts...>;
};

以下是将参数包展开为任意模板的可重用方法:

template <class Wrapper, template <class...> class Template>
struct unwrap;

template <class... Ts, template <class...> class Template>
struct unwrap<wrapper<Ts...>, Template> {
    using type = Template<Ts...>;
};

谢谢你的解决方案。我直接尝试了
ratio\u产品的
template类template
方案的变体,但无法实现。您介意添加一个我的
static\u assert
的工作示例吗?那么这将是向上投票的完美解决方案。谢谢你的解决方案。我直接尝试了
ratio\u产品的
template类template
方案的变体,但无法实现。您介意添加一个我的
static\u assert
的工作示例吗?那么这将是投票的完美解决方案。