OJW
OJW

Reputation: 4632

C++ template function that uses field present in only some data-types?

Is it possible to have a C++ template function which can access different fields in its input data depending on what type of input data was passed to it?

e.g. I have code of the form:

typedef struct
{
  int a;
  int b;
}s1;

typedef struct
{
  int a;
}s2;

template <class VTI_type> void myfunc(VTI_type VRI_data, bool contains_b)
{
  printf("%d", VRI_data.a);

  if(contains_b) // or suggest your own test here
    printf("%d", VRI_data.b); // this line won't compile if VTI_type is s2, even though s2.b is never accessed
}

void main()
{
  s1 data1;
  data1.a = 1;
  data1.b = 2;
  myfunc <s1> (data1, true);

  s2 data2;
  data2.a = 1;
  myfunc <s2> (data2, false);
}

So we want to use field A from many different data types, and that works fine.

However, some data also has a field B that needs to be used - but the code which accesses field B needs to be removed if the template knows it's looking at a data type that doesn't contain a field B.

(in my example, the structures are part of an external API, so can't change)

Upvotes: 5

Views: 3039

Answers (3)

peterchen
peterchen

Reputation: 41116

To elaborate the suggested use of template specialization:

template <class T> void myfunc(T data)
{  
    printf("%d", VRI_data.a);  
}

// specialization for MyClassWithB:
template <>
void myfunc<MyClassWithB>(MyClassWithB data)
{
    printf("%d", data.a);  
    printf("%d", data.b); 
}

However, that requires a specialization per-class, there is no "auto-detection" of b. Also, you repeat a lot of code.

You could factor out that "having b" aspect into a helper template. A simple demonstration:

// helper template - "normal" classes don't have a b
template  <typename T>
int * GetB(T data) { return NULL; }  

// specialization - MyClassWithB does have a b:
template<>
int * GetB<MyClassWithB>(MyClassWithB data) { return &data.b; }

// generic print template
template <class T> void myfunc(T data)
{  
    printf("%d", VRI_data.a);  
    int * pb = GetB(data);
    if (pb)
      printf("%d", *pb); 
}

Upvotes: 5

Naveen
Naveen

Reputation: 73473

If you don't want to hard code S1 & S2 specialization in the code then you can do:

typedef struct
{
  int a;
  int b;
}s1;

typedef struct
{
  int a;
}s2;

template <class T, bool contains_b> 
struct MyFunc
{

    void operator()(T data)
    {
        printf("%d", data.a);
    }

};


template <class T> 
struct MyFunc<T, true>
{
    void operator()(T data)
    {
        printf("%d", data.a);
        printf("%d", data.b); 

    }
};

template<class T, bool contains_b>
void myFunc(T t)
{
    MyFunc<T, contains_b> m;
    m(t);
}

int _tmain(int argc, _TCHAR* argv[])
{
 s1 data1;
  data1.a = 1;
  data1.b = 2;

  myFunc<s1,true>(data1) ;

  s2 data2;
  data2.a = 1;
  myFunc<s2,false>(data2);
  return 0;
}

Upvotes: 0

EFraim
EFraim

Reputation: 13028

Solution 1: You could use template specialization. The specialization might be performed on per-class basis, or on some more general trait.

Upvotes: 3

Related Questions