1

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

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>- 但尝试使用此结果是其他错误。

也许模式匹配

4

2 回答 2

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为您的代码生成。

于 2013-06-26T18:20:02.643 回答
1

因此,在给予的帮助下,我能够想出一些似乎可行的方法。它需要一种用于 char、short、int、long 类型的 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% 的路。

于 2013-06-27T15:26:00.293 回答