с использованием boost mpl лямбда с вариационным шаблоном класса

80
10

Мне сложно понять, почему следующая простая программа не будет компилироваться. У меня есть varadic template class (my_type ниже), который я хочу использовать для преобразования вектора mpl. Следующий фрагмент приводит к ошибке компиляции "/boost/mpl/aux_/preprocessed/gcc/apply_wrap.hpp:38:19:" применить ", следуя ключевому слову" шаблон ", не относится к шаблону".

#include <boost/mpl/vector.hpp>
#include <boost/mpl/transform.hpp>

template <class... T>
struct my_type{};

using namespace boost::mpl;

using test_type = vector<int, double>;

// expected result is vector< my_type<int>, my_type<double> >
using result_type = transform< test_type, my_type<_> >::type;

int main() {

}

Создание my_type для одного параметра шаблона отлично работает, но я хотел бы понять, почему вариационная версия не работает. Заранее спасибо!

спросил(а) 2021-01-19T20:58:27+03:00 9 месяцев, 1 неделя назад
1
Решение
103

Второй аргумент, ожидаемый преобразованием, - это унарная операция, которую вы не проходите.

В вашем случае my_type не является metafunction который ожидает mpl, поскольку он использует список переменных параметров.

metafunction в простейшем случае выставляет type ЬурейиЙ или ststic bool value. Например:

template <typename T>
struct add_pointer {
using type = T*;
};

Обратите внимание, как add_pointer преобразует предоставленный параметр шаблона. Это пример unary операции, так как он принимает только один шаблонный параметр T

В вашем примере my_type является чисто типом и не может использоваться как метафункция или операция, поскольку он не удовлетворяет критериям metafunction как требуется метафазе transform который имеет поле type указывающее преобразованный тип.

В некоторых случаях простой тип шаблона преобразуется в metafunction как описано в разделе " Detailed Reasoning объяснение" ниже.

Ссылка на Doc: http://www.boost.org/doc/libs/1_31_0/libs/mpl/doc/ref/Reference/transform.html

Код:

#include <boost/mpl/vector.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/equal.hpp>

#include <type_traits>
#include <typeindex>
#include <iostream>

template <class... T>
struct my_type{};

using namespace boost::mpl;

using test_type = vector<int, double>;

template <typename T>
struct add_my_type {
using type = my_type<T>;
};

using result_type = typename transform< test_type, add_my_type<_1> >::type;

int main() {
static_assert (equal<result_type, vector< my_type<int>, my_type<double> >>::value, "Nope!!");

std::cout << typeid(result_type).name() << std::endl;
}

LIVE DEMO

Подробное объяснение

Причина, объясняемая выше, довольно кратка, должно быть достаточно, чтобы ответить на вопрос. Но давайте вдаваться в подробности настолько, насколько смогу.

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я не эксперт в boost :: mpl.

В соответствии с комментарием ниже OP, исходный код работает, если мы изменим my_type на:

template <class T>
struct my_type{};

Но это не соответствует тому, что я упоминал ранее, т.е. operation нуждаются в идентификаторе type. Итак, давайте посмотрим, что делает mpl под капотом:

struct transform несколько выглядит так:

template<  
typename Seq1 = mpl::na
, typename Seq2OrOperation = mpl::na
, typename OperationOrInserter = mpl::na
, typename Inserter = mpl::na
>
struct transform {
boost::mpl::eval_if<
boost::mpl::or_<
boost::mpl::is_na<OperationOrInserter>,
boost::mpl::is_lambda_expression<my_type<mpl_::arg<1> > >,
boost::mpl::not_<boost::mpl::is_sequence<my_type<mpl_::arg<1> > > >,
mpl_::bool_<false>,
mpl_::bool_<false>
>,
boost::mpl::transform1<
boost::mpl::vector<int, double>,
my_type<mpl_::arg<1>>,
mpl_::na
>,
boost::mpl::transform2<boost::mpl::vector<int, double>,
my_type<mpl_::arg<1> >,
mpl_::na, mpl_::na>
>

};

Важная часть здесь - is_lambda_expression которая в основном проверяет, соответствует ли ваша Operation требованиям metafunction.

После применения тяжелых механизмов макроса и шаблонов и специализаций вышеупомянутая проверка синтезируется ниже struct:

template<
typename IsLE, typename Tag
, template< typename P1 > class F
, typename L1
>
struct le_result1
{
typedef F<
typename L1::type
> result_;

typedef result_ type;
};

Здесь F является вашим my_type а L1 - placeholder. Таким образом, в сущности, вышеуказанная структура - не что иное, как add_my_type что я показал в своем первоначальном ответе.

Если я прав до сих пор, le_result1 - это operation, которая будет выполняться в вашей sequence.

ответил(а) 2021-01-19T20:58:27+03:00 9 месяцев, 1 неделя назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

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