如何使用C ++中的模板实现重载函数?

时间:2013-01-13 18:27:35

标签: c++ templates overloading

假设我想定义一组函数,每个函数有4个重载,第一个重载采用int32_t类型的单个参数,第二个采用int64_t,第三个 - uint32_t第四个 - uint64_t。对于每个函数,所有重载都具有相同的实现,因此我可以改为定义函数模板:

template <typename T>
void f(T t) {
  // ...
}

然而,这与四次重载不同,因为现在我为每个(整数)类型都有一个单独的函数,可用于实例化ff的实现细节使得它可能不适用于其他整数类型。为了解决这个问题,我可以将函数模板包装在四个重载函数中:

template <typename T>
void f_impl(T t) {
  // ...
}

void f(int32_t value) { f_impl(value); }
void f(int64_t value) { f_impl(value); }
void f(uint32_t value) { f_impl(value); }
void f(uint64_t value) { f_impl(value); }

它可以工作但每个函数需要大量代码(4个函数重载+ 1个函数模板)。有没有办法简化这个?

为了澄清,不希望直接使用模板,因为除了int32_tint64_t以外的其他类型的专业化没有意义(出于实现原因或其他原因), uint32_tuint64_t


我已经尝试过使用std::enable_if了,这个例子最能说明问题所在:

#include <type_traits>
#include <iostream>

template <typename T>
struct is_supported_int {
  static const bool value = false;
};

template <>
struct is_supported_int<int32_t> {
  static const bool value = true;
};

template <>
struct is_supported_int<int64_t> {
  static const bool value = true;
};

// ...

template <typename T, typename = typename std::enable_if<is_supported_int<T>::value, T>::type>
void f(T t) {
// ...
}

int main() {
  short s = 42;
  f(s);
}

与我尝试模拟的带有重载的原始版本不同,此示例将无法编译,因为f将从short的匹配函数集中排除。

不幸的是,Rapptz建议的std::is_integral<T>也没有帮助,因为f的实现细节只能为特定类型定义,而不能为所有整数类型定义。

2 个答案:

答案 0 :(得分:5)

这样的事情会起作用。

#include <type_traits>
#include <iostream>

template<typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
void f(T t) {
    std::cout << "int types only!\n";
}

int main() {
    f(1.234f);
    f(12);
}

f(1.234f)将无法编译,但f(12)将无法编译。

答案 1 :(得分:0)

使用enable_if或静态断言来限制实例化。

#include <type_traits>
#include <cstdint>

template<bool X, bool Y>
struct or_ : std::true_type 
{};

template<>
struct or_<false, false> : std::false_type 
{};

template<typename T>
struct valid_type_for_f :
  or_< std::is_same<T, std::uint32_t>::value,
       std::is_same<T, std::uint64_t>::value> // etc.
{};

// static assert
template<typename T>
T f(T t) {
  static_assert(valid_type_for_f<T>::value, "Not a valid type");
  return t;
}

// enable_if
template<typename T>
typename std::enable_if<valid_type_for_f<T>::value, T>::type
fenable(T t) {
  return t;
}


int main()
{
  float x = 4.2f;
  f(x); // fails
  fenable(x); // fails
  std::uint32_t xx = 23;
  f(xx);
  fenable(xx);
  return 0;
}