Использование 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 boolvalue, Например:

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

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,

После применения некоторого тяжелого механизма и специализаций макросов и шаблонов, вышеприведенная проверка объединяет следующую структуру:

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,

Другие вопросы по тегам