boost mpl序列模式匹配

时间:2013-06-26 17:28:20

标签: c++ boost variadic-templates boost-mpl

我正在尝试编写一个元函数(在haskell中)看起来大致如下:

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

我能够使用roll-my-own自己的可变参数模板序列,但似乎无法弄清楚如何使用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>的列表 - 但尝试使用此结果是其他错误。

可能是模式匹配

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

因此,在给予帮助的情况下,我能够提出似乎有用的东西。它需要一个long用于char,short,int,long类型的特化,以及用于long 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 ++ filt):

#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%的人在那里。