2016-12-07 2 views
2

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

#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 принимать один параметр шаблона отлично работает, но я хотел бы понять, почему VARIADIC версия не работает. Заранее спасибо!

ответ

0

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

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

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

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

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

В вашем примере my_type чисто типа и не может быть использован в качестве metafunction или операций, поскольку она не удовлетворяет критерии metafunction в соответствии с требованиями transform metafunction, который имеет 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.

В соответствии с комментарием ниже по ОП, исходный код работает, если мы изменим 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 metafunction, который в основном проверяет, если ваш 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.

+1

Благодарю вас за помощь. У меня создалось впечатление, что 'my_type <_1>' по существу преобразуется позже в унарный класс метафонов через mpl :: lambda. Я все еще не совсем понимаю, почему это не так, поскольку один аргумент передается 'my_type'. Не могли бы вы объяснить немного больше, почему 'my_type <_1>' не считается допустимым унарным классом метафоров, пожалуйста? – linuxfever

+0

Обновил мой ответ. Надеюсь, теперь это должно быть ясно. – Arunmu

+1

Я боюсь, что не согласен с «как требуется метафоном преобразования, который имеет поле типа, указывающее преобразованный тип». Например, если вы меняете 'my_type' на' template struct my_type {} ', код компилируется и дает желаемый результат, даже если' my_type' до сих пор не раскрывает поле 'type'. – linuxfever

Смежные вопросы