Использование boost mpl lambda с классом шаблонов variadic
Мне трудно понять, почему следующая простая программа не скомпилируется. У меня есть шаблон класса Variadic (my_type
ниже), который я хочу использовать для преобразования вектора mpl. Следующий фрагмент кода приводит к ошибке компиляции "/boost/mpl/aux_/preprocessed/gcc/apply_wrap.hpp:38:19:" apply "после ключевого слова" template "не ссылается на шаблон".
#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
взять один параметр шаблона работает нормально, но я хотел бы понять, почему не работает вариант с вариадической. Заранее спасибо!
1 ответ
Второй аргумент, ожидаемый преобразованием - это унарная операция, которую вы не передаете.
В твоем случае, my_type
это не metafunction
что mpl ожидает, так как он использует список переменных параметров.
metafunction
в простейшем случае выставляет type
typedef или ststic bool
value
, Например:
template <typename T>
struct add_pointer {
using type = T*;
};
Обратите внимание, как add_pointer
преобразует предоставленный параметр шаблона. Это пример unary
операция, так как она принимает только один параметр шаблона T
,
В вашем примере my_type
является чисто типом и не может использоваться как метафункция или операция, так как не удовлетворяет критериям metafunction
в соответствии с требованиями transform
мета-функция, которая имеет type
поле для обозначения преобразованного типа.
В некоторых случаях простой тип шаблона преобразовывается в metafunction
как объяснено в Detailed Reasoning
раздел ниже.
Ссылка на документ: 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;
}
Подробная причина
Причина, объясненная выше, довольно краткая, и ее должно быть достаточно, чтобы ответить на вопрос. Но давайте углубимся в детали настолько, насколько смогу.
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я не эксперт в 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
,
После применения некоторого тяжелого механизма и специализаций макросов и шаблонов, вышеприведенная проверка объединяет следующую структуру:
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
,