2013-06-26 37 views
1

我想写一元函数,其(在Haskell)看起来大致是:升压MPL序列模式匹配

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

我能够做到这一点使用卷我,自己自己的可变参数模板序列,但可以似乎不知道如何使用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。在我自己的roll中,我实际上使用了'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 ++中的bug,因为clang ++会为您的代码生成1

+0

你知道我在那里看到了数字末尾的'l',并想知道它是否有所作为。我解雇了它,因为我的roll-my-own版本工作,我认为'l'在某种程度上是mpl的产物,不一定是g ++。这特别令人恼火,但我认为关键可能是更高层次的抽象。我认为* boost :: mpl :: vector_c :: type'可能会提供更有用的类型。我担心的是文档说这会返回一个vectorn_c类型,这对我来说可能不是很有用。 – nickdmax

+0

是'boost :: mpl :: vector_c :: type'是'boost:mpl :: vector1_c '所以没有太多的帮助。另一个令人恼火的是,即使将矢量类型更改为“mpl :: vector ”,也不允许模板参数T在没有对类型进行硬编码的情况下工作。 – nickdmax

1

所以在给予的帮助下,我能够想出一些似乎可行的东西。它需要一个专用于long的用于char,short,int,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; 
}; 

demangling的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% 。