2013-06-26 6 views
1

Я пытаюсь написать metafunction, который (в Haskell) выглядит примерно так:подталкивания шаблон последовательности MPL соответствие

gather :: [a] -> [a] -> ([a], [a]) 
gather (x:xs) (_:_:ys) = <something using x, xs, and ys> 
...other pattern matches... 

Я был в состоянии сделать это с помощью рулонного моего собственного собственного VARIADIC последовательности шаблонов, но могу Похоже, вы не знаете, как это сделать, используя mpl.

для простоты я пытался эту функцию образца (должен помочь мне понять, что мне нужно):

//get_first :: [a] -> a 
template<class SEQ_C> 
get_first { 
    enum { value = -1 }; 
    typedef get_first<SEQ_C> type; 
}; 

//get_first (x:xs) = x 
template<template<class T, T... S> class SEQ_C, class T, T x, T... xs> 
struct get_first<SEQ_C<T, x, xs...>> { 
    enum { value = x }; 
    typedef get_first<SEQ_C<T, x, xs...>> type; 
}; 

... 

typedef boost::mpl::vector_c<int 1, 2, 3> listA; 
typedef get_first<listA>::type first; 
std::cout << first::value << std::endl; 

выходы -1.

Я пробовал несколько разных способов получить совпадение на данный момент. Я просто принимаю удары в темноте. В документации похоже, что mpl::vector_c<int, x> - это действительно список integral_c<int, x> - но попытка использования этого результата - другие ошибки.

Может быть шаблон

+0

Насколько я могу судить, проблема в том, что последовательности boost :: mpl фактически не используют вариативные шаблоны, а имитируют их. Итак, 'mpl :: vector_c ' становится 'mpl :: vector ' где '2147483647l' повторяется до тех пор, пока мы не достигнем BOOST_MPL_LIMIT_VECTOR_SIZE. В моем ролике я фактически использовал 'template ', который рассказал компилятору, чего ожидать. Я полагаю, что это не стандарт, чтобы попытаться выяснить, как вещи * предполагается * работать: Если вы передаете невариантный тип шаблона в качестве параметра шаблона, должен ли он соответствовать? – nickdmax

ответ

2

Ничего себе, я найти корень проблемы. Посмотрите на сообщение об ошибке (вы можете увидеть, если вы прокомментируете typedef get_first<SEQ_C> type; линии):

error: ‘type’ in ‘struct get_first<boost::mpl::vector_c<int, 1l, 2l, 3l> >’ does not name a type 
//               ^^^

Как вы можете видеть, g++ трактует передаются аргументы, как long, а не как int. Таким образом, если вы измените свою спецификацию на:

template<template<class T, long... S> class SEQ_C, class T, long x, long... xs> 
struct get_first<SEQ_C<T, x, xs...>> { 
    enum { value = x }; 
    typedef get_first<SEQ_C<T, x, xs...>> type; 
}; 

Это сработает.

Конечно, это не решение, я просто покажу, как это будет работать. Я думаю, это ошибка в g ++, так как clang ++ производит 1 для вашего кода.

+0

Вы знаете, что я увидел «l» в конце номеров и подумал, не изменилось ли это. Я отклонил его, потому что моя версия для моего собственного роли работала, я думаю, что «l» - это как-то продукт mpl, а не g ++. Это особенно раздражает, но я думаю, что ключ может быть более высоким уровнем абстракции. Я думаю, что 'boost :: mpl :: vector_c :: type' может дать более полезный тип для работы.Меня беспокоит то, что в документации говорится, что это возвращает тип vectorn_c, который может быть не очень полезен для меня. – nickdmax

+0

yes 'boost :: mpl :: vector_c :: type' is' boost: mpl :: vector1_c 'так что не много помощи. Другая раздражающая вещь заключается в том, что даже изменение векторного типа на 'mpl :: vector ' не позволяет параметру шаблона T работать без жесткого кодирования типа в. – nickdmax

1

Так что с помощью этой справки я смог придумать что-то, что кажется сработавшим. Для этого требуется одна специализация с длиной, которая используется для символов char, short, int, long и оригинального шаблона для длительной работы.

Таким образом, окончательный шаблон выглядит следующим образом:

// get_first :: [a] -> a 
// get_first x:xs = x 
template<class SEQ_C> 
struct get_first { 
    enum { value = -1 }; 
    typedef get_first<SEQ_C> type; 
    typedef typename SEQ_C::value_type value_type; 
    typedef SEQ_C sequence_type; 
}; 

//needed for char/short/int/long 
template<template<class T, long... S> class SEQ_C, class T0, long X, long... XS> 
struct get_first<SEQ_C<T0, X, XS...>> { 
    enum { value = X }; 
    typedef get_first<SEQ_C<T0, X, XS...>> type; 
    typedef T0 value_type; 
    typedef SEQ_C<T0, X, XS...> sequence_type; 
}; 

//needed for long long 
template<template<class T, T... S> class SEQ_C, class T0, T0 X, T0... XS> 
struct get_first<SEQ_C<T0, X, XS...>> { 
    enum { value = X }; 
    typedef get_first<SEQ_C<T0, X, XS...>> type; 
    typedef T0 value_type; 
    typedef SEQ_C<T0, X, XS...> sequence_type; 
}; 

декодирование get_first<SEQ>::sequence_type был весьма показательным. С этой целью я нашел этот кусок коды весьма полезной (если вы не чувствуете, как с помощью C++ ФИЛТРА все время):

#include<typeinfo> 
#include<string> 
#include<cstdlib> 
#include<cxxabi.h> 

std::string demangle(const char* name) { 
    int status; 
    char *realname; 
    std::string retValue; 
    realname = abi::__cxa_demangle(name, NULL, NULL, &status); 
    if (realname != NULL) { 
     retValue = std::string(realname); 
     free(realname); 
    } 
    return retValue; 
} 

template<class T> 
std::string demangle() { return demangle(typeid(T).name()); } 

большое спасибо скоро, кто получил меня 98% пути там ,