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

dud*_*ulu 25 c++ templates

假设我有一个函数的模板,比方说

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

但是,对于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, ...);
    ...      }
  ...
}
Run Code Online (Sandbox Code Playgroud)

当然,由于"T == SpecialType"无效,因此该代码无法编译.那么如何以优雅的方式编写它呢?

Hol*_*Cat 30

它很简单:

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

如果你不能使用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, ...);
Run Code Online (Sandbox Code Playgroud)

(这仅适用于C++ 17.)

  • 我推荐使用`if constexpr`.当然,编译器应该能够优化掉检查,但是检查其他函数调用的有效性可能是昂贵的,特别是如果它涉及额外的模板实例化.此外,不使用`if constexpr`可能是这些函数的维护问题:修改它们的任何人都必须考虑到它们需要有效,即使对于它们永远不会被调用的参数也是如此. (8认同)
  • @JohnLaw是的,`std :: is_same_v`是C++ 17.如果你没有它,请改用`std :: is_same <...> :: value`.`如果constexpr`也是C++ 17,请检查其他答案. (3认同)

Bia*_*sta 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
  } 

  // ...
}
Run Code Online (Sandbox Code Playgroud)

C++ 17之前,您可以使用诸如SFINAE"TAG调度"之类的技术获得相同的结果.

此外,您可以专门参考函数调用的代码部分(简单并避免代码重复).

简单例子在这里:

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
}
Run Code Online (Sandbox Code Playgroud)


πάν*_*ῥεῖ 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);
}
Run Code Online (Sandbox Code Playgroud)

看到它在这里工作.


Yak*_*ont 6

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

这适用于:

template<class V>
auto dispatch( V const& ) {
  return [](auto&&...targets) {
    return std::get<V{}>( std::forward_as_tuple( decltype(targets)(targets)... ) );
  };
}
Run Code Online (Sandbox Code Playgroud)

然后:

 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 );
Run Code Online (Sandbox Code Playgroud)

做你想要的.(它也是一个返回函数返回函数的函数)

实例.

dispatch选择两个lambdas中的一个并在编译时返回它.然后我们用a和调用拾取的lambda b.因此,只有有效的编译类型为ab.