[ACCEPTED]-C++: How to use type in template function to branch?-template-function

Accepted answer
Score: 11

While the solution proposed by Jason works, it's 8 far from idiomatic, and is harder to maintain 7 since the case values in the switch statement 1) have 6 no apparent meaning ("magic numbers") and 5 2) could easily get out of sync with the 4 values in the switch_value<> specializations. I would 3 propose this instead:

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

Invoking Foo::get<> with any 2 type other than int or char will yield a compiler 1 error.

Score: 9

You would need to add a value structure 9 of some type you can use to get the values 8 for your switch-statement from. For instance:

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

The 7 nice thing here is this should throw a compiler 6 error if you use a type that does not have 5 a valid value since the default version 4 of switch_value<T> does not define a member value, so if you 3 haven't specialized the structure for a 2 specific type, then such a template instantiation 1 will fail.

Score: 2

All of these answers are wayyyy overkill.

template <typename T>
T get( int idx )
{
   if ( boost::is_same<T, int>::value)
      return *(T*)&iArr[ idx ];
   else
      return *(T*)&cArr[ idx ];
}

0

Score: 1

You could specialise the member function:

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

Works 3 with msvc++ 2010. Hope this helps.

The switch 2 specialisation suggested by Jason should 1 also work fine.

Score: 1

This is probably overkill for your example, but 8 if you really only need to store one array 7 at a time, then you can use the boost::variant 6 class and a visitor, e.g.,

#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   

The restriction 5 on the variant implied by the GetVisitor 4 class is that all members of the variant 3 must implement:

T operator[](int)

So you could also add, e.g., std::vector 2 and std::deque as potential members of the 1 variant.

Score: 0

I assume this is what you want beside just 2 focusing on template function:

in a .h file

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

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

somewhere 1 you use it like:

Foo<int> foo1;
Foo<char> foo2;
int i  = foo1.get( 2 );
char c = foo2.get( 4 );

More Related questions