【问题标题】:How to compare two typenames for equality in C++?如何在 C++ 中比较两个类型名是否相等?
【发布时间】:2018-08-19 09:16:51
【问题描述】:

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

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”无效。那么如何优雅地写呢?

【问题讨论】:

  • 写一个模板特化来代替怎么样?
  • 可能重复:1234

标签: c++ templates


【解决方案1】:

很简单:

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

如果不能使用 C++17,请将 std::is_same_v&lt;...&gt; 替换为 std::is_same&lt;...&gt;::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。)

【讨论】:

  • 我推荐使用if constexpr。当然,编译器应该能够优化检查,但检查其他函数调用的有效性可能代价高昂,特别是如果它涉及额外的模板实例化。此外,不使用 if constexpr 可能是这些函数的维护问题:任何修改它们的人都必须考虑到它们需要有效,即使对于它们永远不会被调用的参数也是如此。
  • 很好的答案,可爱的 6 票。不幸的是,尽管我很想在我正在使用的编译器上看到这项工作,但它不起作用。这是 C++17 模板/函数吗?
  • @JohnLaw 是的,std::is_same_v 是 C++17。如果没有,请改用std::is_same&lt;...&gt;::valueif constexpr 也是 C++17,请查看其他答案以获取替代方案。
【解决方案2】:

如果你可以使用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 Dispatching”等技术实现相同的结果。

此外,您可以只专门化引用函数调用的代码部分(简单并避免代码重复)。

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

【讨论】:

    【解决方案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);
    }
    

    看到它工作online here

    【讨论】:

      【解决方案4】:

      中,最佳解决方案是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 选择两个 lambdas 之一并在编译时返回它。然后我们用ab 调用选择的lambda。因此,只有有效的会使用 ab 的类型编译。

      【讨论】:

        【解决方案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);
        

        【讨论】:

          猜你喜欢
          • 2017-09-22
          • 2023-03-11
          • 1970-01-01
          • 2014-09-20
          • 2016-03-05
          • 2013-08-18
          • 2011-05-05
          • 2021-05-23
          • 1970-01-01
          相关资源
          最近更新 更多