【问题标题】:Is it possible to overload a template function based on whether the type is an integer type or a floating point type?是否可以根据类型是整数类型还是浮点类型来重载模板函数?
【发布时间】:2018-01-24 23:20:47
【问题描述】:

我想编写只在类型为整数时调用的模板函数,例如 int8, int16, int32, int64, uint8, uint16, uint32, uint64;以及另一个具有不同代码的模板函数(同名),仅适用于 FLOAT 类型 float32、float64 ... 无论如何可以使用 C++ 中的模板函数来完成它? 例如:

template <class T>
void fun(T b)
{
   /// Code for integer type
}


 template <class S>
void fun(S a)
{
   /// Code for floating type
}

【问题讨论】:

  • 相关,但有更好读的技术:stackoverflow.com/q/19985160/1896169
  • 只使用重载——这就是它们的用途
  • @pm100 我不建议有人为所有整数和 2 个浮点类型编写所有重载。这是很多不必要的代码重复
  • 经验(和时间压力)教会我选择一种类型并坚持下去。当然,如果您是图书馆作家,情况可能会有所不同。
  • 使用 SFINAE。一个使用std::is_intergal!is_floating_point,另一个使用反向

标签: c++ function templates


【解决方案1】:

是的,这是可能的。一种方法是使用SFINAE:

template <class T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
void fun(T b)
{
   /// Code for integer type
}


template <class S, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
void fun(S a)
{
   /// Code for floating type
}

注意enable_ifs 的两个条件必须是不相交的,我们可以从std::is_integralstd::is_floating_point 的文档中看到它们是不相交的。如果不是,则条件必须类似于 std::is_integral_v&lt;T&gt; &amp;&amp; !std::is_floating_point_v&lt;T&gt;

这里发生的情况是,如果条件不满足,std::enable_if_t 会使其中一个重载“编译失败”,这意味着由于 SFINAE 根本不考虑重载。


如果您使用的是 C++17,您可能需要考虑改用 if constexpr

template <class T>
void fun(T b)
{
    if constexpr (std::is_integral_v<T>) {
        /// Code for integer type
    } else if constexpr (std::is_floating_point_v<T>) {
        /// Code for floating type
    }
}

【讨论】:

    【解决方案2】:

    根据您的全部意图,在SFINAEstd::enable_if 之外,您也可以使用常规函数重载和/或模板特化:

    #include <iostream>
    #include <cstdint>
    
    template < typename T >
    void fun(T b)
    {
        std::cout << "Generic called: " << b << std::endl;
    }
    
    void fun(int16_t b)
    {
        std::cout << "int16_t: " << b << std::endl;
    }
    
    void fun(int32_t b)
    {
        std::cout << "int32_t: " << b << std::endl;
    }
    
    void fun(float b)
    {
        std::cout << "float: " << b << std::endl;
    }
    
    template <>
    void fun<int64_t>(int64_t b)
    {
        std::cout << "int64_t specialization: " << b << std::endl;
    }
    
    int main(int argc, char** argv)
    {
        double dbl = 3.14159;
        float flt = 1.12345;
        int16_t i16 = 16;
        int32_t i32 = 32;
        fun(dbl);
        fun(flt);
        fun(i16);
        fun(i32);
        fun(5.555f);
        fun(32);
        fun(std::numeric_limits<int64_t>::max());
        return 0;
    }
    

    希望能有所帮助。

    【讨论】:

    • 对于您想要重载所有int8_tint64_tuint8_tuint64_t 的情况,此解决方案有很多代码重复。但是,当我遇到这种情况时,我通常会发现它是不必要的,我可以只重载 int64_tuint64_t 并称之为完成。
    • 我完全同意,@贾斯汀!! OP 的问题暗示他们希望每种类型都有单独的函数,这就是为什么建议保留简单的函数重载,如果这确实是他们的意图。
    【解决方案3】:

    根据SFINAE,我们可以为一种类型设计编译错误,而让另一种类型进入模板替换阶段。在整数类型与浮点类型的情况下,我们可以将与位相关的运算符用于整数,如~。例如,

    #include <iostream>
    
    template <typename T, T=~0>
    void f_(T a, int)  // additional tags for unambiguous overloading, same below
    {
        std::cout << a << " is of integral type." << std::endl;
    }
    
    template <typename T>
    void f_(T a, char)
    {
        std::cout << a << " is of floating-point type." << std::endl;
    }
    
    template <typename T>
    void f(T a)
    {
        f_<T>(a, 0);
    }
    
    
    int main()
    {
        f<char>('a');
        f<int>(0);
        f<float>(1.5f);
        f<double>(2.5);
        return 0;
    }
    

    给予

    a is of integral type.
    0 is of integral type.
    1.5 is of floating-point type.
    2.5 is of floating-point type.
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-31
      • 2012-10-25
      • 1970-01-01
      • 2015-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-23
      相关资源
      最近更新 更多