如何在C ++中比较两个类型名称是否相等?

时间:2018-08-19 09:16:51

标签: c++ templates

假设我有一个函数模板,例如

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”无效,因此不会编译此代码。那我怎么用一种优雅的方式写它呢?

5 个答案:

答案 0 :(得分:31)

这很简单:

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

如果您不能使用C ++ 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, ...);

(仅在C ++ 17中有效。)

答案 1 :(得分:18)

如果可以使用 C ++ 17 ,则可以以非常干净的方式(使用constexpris_same)获得结果:

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

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

  // ...
}

C ++ 17 之前,您可以使用SFINAE或“ TAG调度”之类的技术来获得相同的结果。

此外,您可以 specialize 引用函数调用的代码部分(轻松避免代码重复)。

一个简短的示例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
}

答案 2 :(得分:12)

您始终可以使用模板专用化,而不是对模板参数进行类型比较。这是一个简化的工作示例:

#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);
}

看到它工作online here

答案 3 :(得分:6)

中,最好的解决方案是if constexpr

中,此方法有效:

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 );

做您想要的。 (这也是返回函数的函数,返回函数的函数)

Live example

dispatch选择两个lambda之一,并在编译时将其返回。然后,我们用ab调用选取的lambda。因此,只有有效的那个才会使用ab的类型进行编译。

答案 4 :(得分:1)

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);