0

我有一个看起来像这样的模板函数:

template <class T> void foo(T* t)
{
    //do stuff using:
    someArray[idx]; //idx depends on T
}

有几种可能的类型T,所以我的方法是在一个未命名的命名空间中做这样的事情:

struct Sentinel;
template <class T> struct Offsets {};
#define GENIDX(T,NUM) template <> struct Offsets<T> {static const int idx = NUM;};

GENIDX(Fox, 0)
GENIDX(Cat, 1)
GENIDX(Rat, 2)

GENIDX(Sentinel, 3)

static const size_t numTypes = Offsets<Sentinel>::idx;

然后稍后,成员数组someArray被声明为someArray[numTypes];

并且 foo 方法是这样实现的:

template <class T> void foo(T* t)
{
    typedef Offsets<T> offset_t;
    someArray[offset_t::idx]; //idx depends on T
}

如果有人需要向系统添加新类型,他们只需添加一个新类型GENIDX,一切都会正常工作。唯一的麻烦是,如果有人想要添加,比如说,Wolf混合,但他们希望它在逻辑上出现,然后Cat他们必须手动调整剩余的索引。我想知道是否有一种方法不需要宏中的数字索引,而是让它们自动按顺序生成。像这样的东西,除了以下不起作用:

size_t numTypes = 0;
template <class T> struct Offsets {};
#define GENIDX(T) template <> struct Offsets<T> {static const int idx = numTypes++;};

GENIDX(Fox)
GENIDX(Cat)
GENIDX(Rat)

之后numTypes将正确包含数组的大小。当在组合中的任何地方插入新的专业时,这不需要任何索引管理,如果至少从好奇的角度来看,知道如何做到这一点会很有趣。

虽然这样做,但在我意识到我__COUNTER__的 gcc 版本没有之后:

template <class T> struct Offsets {};
#define GENIDX(T) \
    template <> struct Offsets<T> \
    { \
      #include BOOST_PP_UPDATE_COUNTER() \
      static const int idx = COUNTER; \
    };

但上面失败了,因为我不能#include在宏里面说......

4

2 回答 2

2

C++11 解决方案

一些包括和一个助手:

#include <cstddef>
#include <tuple>
#include <type_traits>
#include <iostream>

template < typename T0, typename T1 >
constexpr auto c_min(T0 p0, T1 p1)
-> typename std::common_type<T0, T1>::type
{
    return p0 < p1 ? p0 : p1;
}

您的类型和这些类型的“集合”:

struct Fox {};
struct Cat {};
struct Rat {};

using my_types = std::tuple < Fox, Cat, Rat >;

两个功能:

// returns the size of the collection
constexpr std::size_t get_size()
{
    return std::tuple_size<my_types>::value;
}


// `get_index < type > ();` returns the index of a type in that collection

// no definition required, only used to suppress error messages
template < typename, std::size_t >
constexpr std::size_t get_index(std::integral_constant<bool, true>);

template < typename T, std::size_t t = 0 >
constexpr std::size_t get_index(std::integral_constant<bool, false> = {})
{
    using Current = typename std::tuple_element<t, my_types>::type;
    using IsSame = std::is_same<T, Current>;

    static_assert(IsSame{} || t+1 < get_size(),
                  "Unknown type: Passed type not in tuple.");

    using IsError = std::integral_constant< bool,
                                            (IsSame{} || t+1 == get_size()) >;

    return IsSame{} ? t : get_index<T, t+1>( IsError{} );
}

使用示例:

int someArray[ get_size() ] = {0};


template < class T >
void foo(T* t)
{
    someArray[ get_index<T>() ] = 42;
}


int main()
{
    std::cout << "Array before modification: ";
    for(auto const& e : someArray)
    {
        std::cout << e << ", ";
    }
    std::cout << std::endl;

    struct Cow {};
    Cow f;
    foo(&f);

    std::cout << "Array after modification: ";
    for(auto const& e : someArray)
    {
        std::cout << e << ", ";
    }
    std::cout << std::endl;
}
于 2013-05-21T20:40:22.197 回答
0

也许你可以使用__COUNTER__gcc而且VC只有我认为)。每次使用它时,它都会扩展为从 0 开始递增的整数值序列。

template <class T> struct Offsets {};
#define GENIDX(T) template <> struct Offsets<T> {static const int idx = __COUNTER__;};
于 2013-05-21T17:17:30.063 回答