Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to compare two typenames for equality in C++?

Tags:

c++

templates

Suppose I have a template of a function, say

template<typename T>
func(T a, T b, ...) {
  ...
  for (const auto &single : group) {
    ...
    auto c = GivenFunc1(a, b, single, ...);
    ...      }
  ...
}

However, for T being a special type, say "SpecialType", I want c being calculated by "GivenFunc2" rather than "GivenFunc1". However, I would not like to write a specialization for "SpecialType", since there will be a huge code duplication. So I want the template function being something like

template<typename T>
func(T a, T b, ...) {
  ...
  for (const auto &single : group) {
    ...
    auto c = (T == SpecialType) ? GivenFunc2(a, b, single, ...)
                                : GivenFunc1(a, b, single, ...);
    ...      }
  ...
}

Of course, this code does not compile since "T == SpecialType" is not valid. So how do I write it in an elegant way?

like image 565
dudulu Avatar asked Sep 10 '25 17:09

dudulu


2 Answers

It's as simple as:

auto c = std::is_same_v<T, SpecialType> ? GivenFunc2(a, b, single, ...)
                                        : GivenFunc1(a, b, single, ...);

If you can't use C++17, replace std::is_same_v<...> with std::is_same<...>::value.

But for this approach to work, both function calls have to be valid for every T you want to use, even if in reality one of them won't be executed.


If it's not the case, you can resort to if constexpr:

your_type_here c;
if constexpr (std::is_same_v<T, SpecialType>)
    c = GivenFunc2(a, b, single, ...);
else
    c = GivenFunc1(a, b, single, ...);

(This works only in C++17.)

like image 196
HolyBlackCat Avatar answered Sep 13 '25 02:09

HolyBlackCat


If you can use C++17, you can achieve the result in a very clean way (with constexpr and is_same):

template<typename T>
func(T a, T b, ...) {
  // ...

  if constexpr (std::is_same_v<T, SpecialType>) {
    // call GivenFunc2
  } else {
    // call GivenFunc1
  } 

  // ...
}

Pre C++17 you can achieve the same result using techniques such as SFINAE or "TAG Dispatching".

Additionally, you can just specialize the portion of the code referring to the function call (easy and avoid code duplication).

A short example here:

template <typename T>
struct DispatcherFn {
  auto operator()(const T&, int) {
      // call GivenFunc1
  }
};

template <>
struct DispatcherFn<SpecialType> {
  auto operator()(const SpecialType&, int) {
    // GivenFunc2
  }
};

template <typename T>
void func(const T& t) {
  // ... code ...
  auto c = DispatcherFn<T>()(t, 49);  // specialized call
}
like image 34
BiagioF Avatar answered Sep 13 '25 03:09

BiagioF