Как сравнить два типа для равенства в C++?
Предположим, у меня есть шаблон функции, например
template<typename T>
func(T a, T b, ...) {
...
for (const auto &single : group) {
...
auto c = GivenFunc1(a, b, single, ...);
... }
...
}
Однако, если T является особым типом, скажем, "SpecialType", я хочу, чтобы c
был рассчитан с помощью "GivenFunc2", а не "GivenFunc1". Тем не менее, я бы не хотел писать специализацию для "SpecialType", так как будет большое дублирование кода. Поэтому я хочу, чтобы функция шаблона была чем-то вроде
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, ...);
... }
...
}
Конечно, этот код не компилируется, так как "T == SpecialType" недействителен. Итак, как мне написать его элегантным способом?
Ответы
Ответ 1
Это так просто:
auto c = std::is_same_v<T, SpecialType> ? GivenFunc2(a, b, single, ...)
: GivenFunc1(a, b, single, ...);
Если вы не можете использовать С++ 17, замените std::is_same_v<...>
на std::is_same<...>::value
.
Но для этого подхода к работе оба вызова функций должны быть действительными для каждого T
вы хотите использовать, даже если на самом деле один из них не будет выполнен.
Если это не так, вы можете прибегнуть к 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, ...);
(Это работает только в С++ 17.)
Ответ 2
Если вы можете использовать С++ 17, вы можете добиться результата очень constexpr
способом (с помощью constexpr
и is_same
):
template<typename T>
func(T a, T b, ...) {
// ...
if constexpr (std::is_same_v<T, SpecialType>) {
// call GivenFunc2
} else {
// call GivenFunc1
}
// ...
}
Pre С++ 17 вы можете достичь того же результата, используя такие методы, как SFINAE
или "TAG Dispatching".
Кроме того, вы можете просто специализировать часть кода, ссылаясь на вызов функции (легко и избегать дублирования кода).
Короткий пример здесь:
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
}
Ответ 3
Вы всегда можете использовать специализированные шаблоны вместо того, чтобы выполнять типовые сравнения параметров шаблона. Здесь упрощенный, рабочий пример:
#include <iostream>
#include <string>
template<typename T>
int GivenFunc1(T a, T b) {
std::cout << "GivenFunc1()" << std::endl;
return 0;
}
template<typename T>
int GivenFunc2(T a, T b) {
std::cout << "GivenFunc2()" << std::endl;
return 1;
}
template<typename T>
void func(T a, T b) {
auto c = GivenFunc2(a, b);
std::cout << c << std::endl;
}
template<>
void func(std::string a, std::string b) {
auto c = GivenFunc1(a, b);
std::cout << c << std::endl;
}
int main() {
func(2,3);
std::string a = "Hello";
std::string b = "World";
func(a,b);
}
Смотрите, как он работает в Интернете здесь.
Ответ 4
В c++17 лучшим решением является if constexpr
.
В c++14 это работает:
template<class V>
auto dispatch( V const& ) {
return [](auto&&...targets) {
return std::get<V{}>( std::forward_as_tuple( decltype(targets)(targets)... ) );
};
}
затем:
auto c = dispatch( std::is_same<T, SpecialType>{} )
(
[&](auto&& a, auto&& b){ return GivenFunc2(a, b, single...); },
[&](auto&& a, auto&& b){ return GivenFunc1(a, b, single, ...); }
)( a, b );
делает то, что вы хотите. (Это также функция, которая возвращает функцию, возвращающую функцию)
Живой пример.
dispatch
выбирает один из двух лямбда и возвращает его во время компиляции. Затем мы вызываем выбранную лямбду с a
и b
. Таким образом, только действительный один скомпилирован с типом для a
и b
.
Ответ 5
Преобразуйте GivenFunc1
в функтор и специализируйтесь на этом.
template <class T>
class GivenFunc
{
X operator()(T a, T b, Y single)
{
...
}
}
template <>
class GivenFunc<SpecialType>
{
X operator()(SpecialType a, SpecialType b, Y single)
{
...
}
}
Тогда вы можете сказать
auto c = GivenFunc<T>()(a, b, single);