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 >;

2 つの機能:

// 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 に答える