【问题标题】:How can I unwrap a parameter pack wrapper?如何解开参数包包装器?
【发布时间】:2018-08-08 10:41:40
【问题描述】:

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

我的代码如下:

#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,"");
}

【问题讨论】:

    标签: c++ templates variadic-templates compile-time


    【解决方案1】:

    这是一种将参数包解包到任意模板中的可重用方法:

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

    这会产生以下static_assert,它可以满足您的期望:

    static_assert(
        unwrap<
            wrapper<std::ratio<5>, std::ratio<5>, std::ratio<4>>,
            ratio_product
        >::type::value == 100, "");
    

    【讨论】:

    • 感谢您的解决方案。我直接尝试了ratio_producttemplate &lt;class...&gt; class Template 方案的变体,但我无法让它工作。
    • 您介意添加我的static_assert 的工作示例吗?那么这将是投票的完美解决方案。
    【解决方案2】:

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

    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;
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-20
      • 2023-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多