Home > front end >  C conditional type at run time with templates
C conditional type at run time with templates

Time:02-03

I have a template function that is specialized with two types, as:

class A () { /* ... */ };
class B () { /* ... */ };

template<class T>
void foo (T &out);

template<>
void foo<A> (A &out) { /* ... */ }

template<>
void foo<B> (B &out) { /* different code ... */ }

I either call foo with A or B depending on a run-time condition and I need to allocate either A or B before calling foo. After calling foo there needs to be other code that is the same with both A or B, resulting in something like this:

if (condition) {
  A obj;
  foo (obj);
  /* code using obj */
} else {
  B obj;
  foo (obj);
  /* same code using obj */
}

Since the only difference is in the declaration of obj, I would like to avoid repeating the same code, ideally like auto obj = condition ? A() : B(); which of course is not allowed run time. Is there any other way to obtain this in a clean way?

CodePudding user response:

The common code could be a function template, or a generic lambda (depending on how much code there is and how readable the result:

if (condition) {
  A obj;
  foo (obj);
  /* code using obj */
} else {
  B obj;
  foo (obj);
  /* same code using obj */
}

Could transform into something like:

auto common_code = [](auto && obj) { 
    foo(obj); 
    /* code using obj */
};

if (condition) {
  common_code(A{});
} else {
  common_code(B{});
}

Another thing worth noting, foo does not need to be a template, and generally speaking, function template specializations are discouraged (as the specializations don't participate in overload resolution, and can be surprising).

You can just write two non-template foo functions, one that takes A& and the other that takes a B&. This is simpler and more obvious code.

CodePudding user response:

If you're passing either an A or B object as an (in-)out argument for mostly common code with some select specialized behavior, simply add a function template that delegates the non-common work to foo and contains the common work by itself.

template <typename T, typename = std::enable_if_t<std::is_same_v<T, A> ||
                                                  std::is_same_v<T, B>>>
void do_non_const_things_with_a_or_b(T &obj) {
  foo(obj); // specialized for A or B

  // common code for A and B
}

void f(bool condition) {
  if (condition) {
    A obj;
    do_non_const_things_with_a_or_b(obj);
  } else {
    B obj;
    do_non_const_things_with_a_or_b(obj);
  }
}
  •  Tags:  
  • Related