12

私はテンプレートにあまり慣れていません。テンプレートの種類に基づいて取得する配列を選択する get というテンプレート関数を作成するにはどうすればよいですか? 以下の例を参照してください。

struct Foo
{
    int iArr[10];
    char cArr[10];

    // How to pick array here based on template type?
    template < typename T >
    T get( int idx )
    {
        // This does NOT work!
        switch ( T )
        {
        case int:
            return iArr[ idx ];
        case char:
            return cArr[ idx ];
        }
    }
};

// Expected behaviour of get()
Foo foo;
int i  = foo.get< int >( 2 );
char c = foo.get< char >( 4 );
4

6 に答える 6

11

Jason によって提案された解決策は機能しますが、慣用的なものとはほど遠いものでありcase、ステートメントの値にはswitch1) 明確な意味がなく (「マジック ナンバー」)、2) ステートメントの値と簡単に同期しなくなる可能性があるため、維持するのが難しくなります。switch_value<>専門分野。代わりにこれを提案します:

struct Foo {
    Foo() : iArr(), cArr() { }

    template<typename T>
    T get(std::size_t const idx) const     {
        return Foo::get_dispatcher<T>::impl(*this, idx);
    }

private:
    int iArr[10];
    char cArr[10];

    template<typename T>
    struct get_dispatcher;
};

template<>
struct Foo::get_dispatcher<int> {
    static int impl(Foo const& foo, std::size_t const idx) {
        return foo.iArr[idx];
    }
};

template<>
struct Foo::get_dispatcher<char> {
    static char impl(Foo const& foo, std::size_t const idx) {
        return foo.cArr[idx];
    }
};

またはFoo::get<>以外の型で呼び出すと、コンパイラ エラーが発生します。intchar

于 2011-06-23T03:10:48.827 に答える
9

switch-statement の値を取得するために使用できる型の値構造を追加する必要があります。例えば:

template<typename T>
struct switch_value {};

template<>
struct switch_value<int>
{
    enum { value = 1 };
};

template<>
struct switch_value<char>
{
    enum { value = 2 };
};

//then inside you structure Foo
template <typename T>
T get( int idx )
{
    switch ( switch_value<T>::value )
    {
    case 1:
        return iArr[ idx ];
    case 2:
        return cArr[ idx ];
    }
}

ここでの良い点は、の既定のバージョンでswitch_value<T>は member が定義されていないため、有効な値を持たない型を使用するとコンパイラ エラーがスローされることですvalue。そのため、特定の型の構造を特殊化していない場合は、そのようなテンプレートのインスタンス化は失敗します。

于 2011-06-23T02:27:13.557 に答える
1

メンバー関数を特殊化できます。

struct foo
{
    int  iArr[10];
    char cArr[10];

    template<typename T>
    T &get(int ipos) { assert( false && "Foo.get: Invalid type!" ); return T(); }

    template<>
    int &get<int>(int ipos) { return iArr[ipos]; }

    template<> 
    char &get<char>(int ipos) {return cArr[ipos]; }

    // add more specialisations for any other types...
};

msvc++ 2010 で動作します。

Jason によって提案されたスイッチの特殊化も正常に機能するはずです。

于 2011-06-23T02:42:48.143 に答える
1

これはおそらくあなたの例ではやり過ぎですが、実際に一度に 1 つの配列のみを格納する必要がある場合は、boost::variant クラスとビジターを使用できます。

#include <boost/variant.hpp>
#include <iostream>

template< typename T >
class GetVisitor : public boost::static_visitor<T>
{
  public:
    GetVisitor(int index) : index_(index) {};

    template <typename U >
    T operator() (U const& vOperand) const
    {
        return vOperand[index_];
    }

  private:
    int index_;
};


int main ()
{
    int  iArr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    char cArr[10] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' };

    boost::variant<int*, char*>  intVariant(iArr);   //- assign integer array to variant
    boost::variant<int*, char*>  charVariant(cArr);  //- assign character array to another variant

    int  testInt  = boost::apply_visitor(GetVisitor<int>(2),  intVariant);  
    char testChar = boost::apply_visitor(GetVisitor<char>(9), charVariant);

    std::cout << "returned integer is "   << testInt  << std::endl;
    std::cout << "returned character is " << testChar << std::endl;

    return 0;
}

output is:   
returned integer is 3   
returned character is j   

GetVisitor クラスによって暗示されるバリアントの制限は、バリアントのすべてのメンバーが実装する必要があることです。

T operator[](int)

そのため、たとえば std::vector と std::deque をバリアントの潜在的なメンバーとして追加することもできます。

于 2011-06-23T12:02:26.533 に答える
0

テンプレート機能に焦点を当てるだけでなく、これがあなたが望むものだと思います:

.h ファイルで

template < typename T >
struct Foo
{
    T arr[10];

    T get( int idx )
    {
      return arr[ idx ];
    }
};

どこかで次のように使用します:

Foo<int> foo1;
Foo<char> foo2;
int i  = foo1.get( 2 );
char c = foo2.get( 4 );
于 2013-07-30T18:56:52.327 に答える