我想实现一个处理所有简单C++类型的函数(还有 STL 容器和更多类型,但它们没有给我 headakes),使用处理所有其他类型的泛型函数,如下所示:
template <typename T>
void dostuff(T& arg)
{ cout << "generic version" << endl; }
void dostuff(int& arg)
{ cout << "something useful" << endl; }
void dostuff(unsigned int& arg)
{ cout << "something slightly different" << endl; }
void dostuff(short& arg)
{ cout << "something slightly different again" << endl; }
// ...and so on for all integer types...
在这里,我将自己限制为整数类型,因为它们造成了所有麻烦。当然,如果我为同一类型实现两次函数,编译器会抱怨。当混合unsigned int
和std::size_t
之类的东西时会发生这种情况;它适用于我的系统,但无法在 32 位平台上编译。我理解这个问题,但我不知道如何实现便携式解决方案。
我认为最系统的方法是使用 std::int8_t (std::uint8_t, 16, 32, 64) 系列类型,因为它们不会重叠并且旨在覆盖可用范围。事实证明,这还不够,如以下代码所示:
#include <type_traits>
#include <cstdint>
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
cout << "SIZE:" << endl;
cout << "sizeof(unsigned long) = " << sizeof(unsigned long) << endl;
cout << "sizeof(unsigned long long) = " << sizeof(unsigned long long) << endl;
cout << "sizeof(std::size_t) = " << sizeof(std::size_t) << endl;
cout << "sizeof(std::uint64_t) = " << sizeof(std::uint64_t) << endl;
cout << endl;
cout << "SIGNED?" << std::boolalpha << endl;
cout << std::is_signed<unsigned long>::value << endl;
cout << std::is_signed<unsigned long long>::value << endl;
cout << std::is_signed<std::size_t>::value << endl;
cout << std::is_signed<std::uint64_t>::value << endl;
cout << endl;
cout << "SAME?" << endl;
cout << std::is_same<unsigned long, unsigned long long>::value << endl;
cout << std::is_same<unsigned long, std::size_t>::value << endl;
cout << std::is_same<unsigned long, std::uint64_t>::value << endl;
cout << std::is_same<unsigned long long, std::size_t>::value << endl;
cout << std::is_same<unsigned long long, std::uint64_t>::value << endl;
cout << std::is_same<std::size_t, std::uint64_t>::value << endl;
}
在我的 64 位 MacOS 系统上,带有 clang 3.8,它给出了以下输出:
SIZE:
sizeof(unsigned long) = 8
sizeof(unsigned long long) = 8
sizeof(std::size_t) = 8
sizeof(std::uint64_t) = 8
SIGNED?
false
false
false
false
SAME?
false
true
false
false
true
false
所以我有四种 64 位无符号整数类型,但它们实际上只指两种不同的类型。还有更多的候选人,如std::uintptr_t
、std::ptrdiff_t
和std::uint_fast64_t
,我什至不知道这个名单是否完整。哪些类型是相同的定义对我来说看起来很武断,尽管我看到对于我面临的确切问题,我们希望将long
和long long
视为不同。
问题:有没有办法为不同整数类型的详尽列表实现上述函数,这样我就不会在不同的平台上遇到麻烦?如果是这样,这个列表是什么?如果不是,实现所需行为的最佳方法是什么(处理所有整数类型、未知类型的有意义的默认行为、可移植解决方案)?
由于您尝试为每个特定的整型类型做一些不同的事情,因此即使您可以枚举程序中的所有类型,也无法编造特定的特殊逻辑。
相反,我建议的是根据需要实现short
、int
、unsigned
等的特殊逻辑,并放置一个静态断言,说明is_integral<T>
在您的主模板中false
,并显示一条消息,即它正在使用不受支持的整数类型调用,该整数类型需要确定和编写自定义逻辑。
专门针对所有积分类型通常是一个非常糟糕的主意。根据评论中的讨论,我假设对类型的大小和符号进行静态调度会适合您。这是如何完成的:
#include <iostream>
#include <type_traits>
template <typename T, unsigned Size, bool Signed>
struct foo_impl;
template <typename T>
struct foo_impl<T, 1, false>
{
static void foo (T & x) { std::cout << x << " is unsigned 8-bit" << std::endl; }
};
template <typename T>
struct foo_impl<T, 1, true>
{
static void foo (T & x) { std::cout << x << " is signed 8-bit" << std::endl; }
};
template <typename T>
struct foo_impl<T, 2, false>
{
static void foo (T & x) { std::cout << x << " is unsigned 16-bit" << std::endl; }
};
// more specializations ...
template <typename T>
void foo (T & x)
{
// dispatch based on size & signedness
foo_impl<T, sizeof(T), std::is_signed<T>::value>::foo(x);
}
int main ( )
{
char a = 5;
std::uint8_t b = 6;
unsigned short c = 7;
foo(a);
foo(b);
foo(c);
}
生活在 ideone 上