假设我想定义一组函数,每个函数有4个重载,第一个重载采用int32_t
类型的单个参数,第二个采用int64_t
,第三个 - uint32_t
第四个 - uint64_t
。对于每个函数,所有重载都具有相同的实现,因此我可以改为定义函数模板:
template <typename T>
void f(T t) {
// ...
}
然而,这与四次重载不同,因为现在我为每个(整数)类型都有一个单独的函数,可用于实例化f
。 f
的实现细节使得它可能不适用于其他整数类型。为了解决这个问题,我可以将函数模板包装在四个重载函数中:
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_t
,int64_t
以外的其他类型的专业化没有意义(出于实现原因或其他原因), uint32_t
和uint64_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
的实现细节只能为特定类型定义,而不能为所有整数类型定义。
答案 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;
}