【发布时间】:2014-04-15 13:55:09
【问题描述】:
Type traits to get result of promotion from operator
对此的后续问题是否有一种仅使用 C++98 不提升的好方法?
【问题讨论】:
Type traits to get result of promotion from operator
对此的后续问题是否有一种仅使用 C++98 不提升的好方法?
【问题讨论】:
只要你只需要关心标准的内置类型,你就可以这样做:
template <int> struct plus_helper;
template <> struct plus_helper< 1> { typedef char type; };
template <> struct plus_helper< 2> { typedef signed char type; };
template <> struct plus_helper< 3> { typedef unsigned char type; };
template <> struct plus_helper< 4> { typedef short type; };
template <> struct plus_helper< 5> { typedef unsigned short type; };
template <> struct plus_helper< 6> { typedef int type; };
template <> struct plus_helper< 7> { typedef unsigned int type; };
template <> struct plus_helper< 8> { typedef long type; };
template <> struct plus_helper< 9> { typedef unsigned long type; };
template <> struct plus_helper<10> { typedef float type; };
template <> struct plus_helper<11> { typedef double type; };
template <> struct plus_helper<12> { typedef long double type; };
template <> struct plus_helper<13> { typedef wchar_t type; };
template <typename T1, typename T2>
struct plus {
private:
static char (&f(char))[1];
static char (&f(signed char))[2];
static char (&f(unsigned char))[3];
static char (&f(short))[4];
static char (&f(unsigned short))[5];
static char (&f(int))[6];
static char (&f(unsigned int))[7];
static char (&f(long))[8];
static char (&f(unsigned long))[9];
static char (&f(float))[10];
static char (&f(double))[11];
static char (&f(long double))[12];
static char (&f(wchar_t))[13];
public:
typedef typename plus_helper<sizeof(f(*(T1*)0 + *(T2*)0))>::type type;
};
template <typename T1, typename T2>
struct plus<T1 *, T2> {
typedef T1 *type;
};
template <typename T1, typename T2>
struct plus<T1, T2 *> {
typedef T2 *type;
};
请注意,我要求可以添加 T1 和 T2。如果它们不可能,则不一定会给出错误。另请注意,我没有省略比int 更短的类型。内置的+ 运算符永远无法返回它们,但它们是自定义operator+ 的有效返回类型。
不幸的是,如果您还需要担心其他类型,例如自定义结构,那么这种方法将不起作用,虽然我很乐意被证明是错误的,但我认为不可能做到这一点工作。
【讨论】:
可能不是最好的方法,但这就是我得到的......
template <bool value,typename T,typename J>
struct conditional{typedef T type;};
template <typename T,typename J>
struct conditional<false,T,J>{typedef J type;};
template <typename T, typename J>
struct is_equal
{
enum {value = false};
};
template <typename T>
struct is_equal<T,T>
{
enum {value = true};
};
namespace
{
template <typename T, typename J, typename K, typename L>
struct math_t
{
typedef typename conditional<
is_equal<T,K>::value || is_equal<J,K>::value,
K,
L>::type type;
};
}
template <typename T, typename J>
struct math_type
{
typedef typename math_t<T,J,long double,
typename math_t<T,J,double,
typename math_t<T,J,float,
typename math_t<T,J,long long unsigned int,
typename math_t<T,J,long long int,
typename math_t<T,J,long unsigned int,
typename math_t<T,J,long int,
typename math_t<T,J,unsigned int,
int>::type>::type>::type>::type>::type>::type>::type>::type type;
};
【讨论】:
long int 和unsigned int 时会发生什么。结果取决于实现,但在我的系统上,它是unsigned long int,这不是您的模板提供的。
我在这里讨论了一个类似的问题:https://stackoverflow.com/a/2450157/34509。重新粘贴我的代码,因为这似乎是您所追求的。详细解释请看参考答案
// typedef eiher to A or B, depending on what integer is passed
template<int, typename A, typename B>
struct cond;
#define CCASE(N, typed) \
template<typename A, typename B> \
struct cond<N, A, B> { \
typedef typed type; \
}
CCASE(1, A); CCASE(2, B);
CCASE(3, int); CCASE(4, unsigned int);
CCASE(5, long); CCASE(6, unsigned long);
CCASE(7, float); CCASE(8, double);
CCASE(9, long double);
#undef CCASE
// for a better syntax...
template<typename T> struct identity { typedef T type; };
// different type => figure out common type
template<typename A, typename B>
struct promote {
private:
static A a;
static B b;
// in case A or B is a promoted arithmetic type, the template
// will make it less preferred than the nontemplates below
template<typename T>
static identity<char[1]>::type &check(A, T);
template<typename T>
static identity<char[2]>::type &check(B, T);
// "promoted arithmetic types"
static identity<char[3]>::type &check(int, int);
static identity<char[4]>::type &check(unsigned int, int);
static identity<char[5]>::type &check(long, int);
static identity<char[6]>::type &check(unsigned long, int);
static identity<char[7]>::type &check(float, int);
static identity<char[8]>::type &check(double, int);
static identity<char[9]>::type &check(long double, int);
public:
typedef typename cond<sizeof check(0 ? a : b, 0), A, B>::type
type;
};
// same type => finished
template<typename A>
struct promote<A, A> {
typedef A type;
};
例如
int main() {
promote<char, short>::type a;
int *p0 = &a;
promote<float, double>::type b;
double *p1 = &b;
promote<char*, string>::type c;
string *p2 = &c;
}
【讨论】: