Как я могу развернуть оболочку пакета параметров?

78
11

Я хочу делать вычисления с использованием типов 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,"");
}

спросил(а) 2021-01-25T18:55:42+03:00 4 месяца, 2 недели назад
1
Решение
62

Здесь многоразовый способ развернуть пакет параметров в произвольный шаблон:

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

ответил(а) 2021-01-25T18:55:42+03:00 4 месяца, 2 недели назад
45

Я нашел решение. Используя специализированную специализацию, вы можете извлечь пакет параметров из оболочки:

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

ответил(а) 2021-01-25T18:55:42+03:00 4 месяца, 2 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема