#include <cstdlib>
#include <stdarg.h>
#include <type_traits>
// Utility type if / else
template <typename T, typename U, bool choose>
struct TifChooseU { };
template <typename T, typename U>
struct TifChooseU <T, U, true> {
using type = T;
};
template <typename T, typename U>
struct TifChooseU <T, U, false> {
using type = U;
};
// Default - No Promotion
template <typename T>
struct promote_me {
using type = T;
};
// http://en.cppreference.com/w/cpp/language/implicit_cast - Let's go in order
// Signed char - int
template <>
struct promote_me <signed char> {
using type = int;
};
// Signed short - int
template <>
struct promote_me <signed short> {
using type = int;
};
// Unsigned char - int or unsigned int, dependent on inter-stellar configuration
template <>
struct promote_me <unsigned char> {
// Doesn't compile without the parens around the operator >
using type = TifChooseU <int, unsigned int, (sizeof(int) > sizeof(unsigned char))>::type;
};
// Unsigned short - int or unsigned int, dependent on inter-stellar configuration
template <>
struct promote_me <unsigned short> {
// Doesn't compile without the parens around the operator >
using type = TifChooseU <int, unsigned int, (sizeof(int) > sizeof(short))>::type;
};
// Char - dispatch to unsigned / signed char
template <>
struct promote_me <char> :
promote_me <TifChooseU <signed char, unsigned char,
std::is_signed<char>::value>::type> {};
// Wchar_t - int, unsigned int, long, unsigned long, long long, unsigned long long
// dependent on the amount of goats recently sacrificed
template <>
struct promote_me <wchar_t> {
using type =
TifChooseU <
TifChooseU <int,
TifChooseU<long, long long, (sizeof(long) > sizeof(wchar_t))>::type,
(sizeof(int) > sizeof(wchar_t))>::type,
TifChooseU <unsigned int,
TifChooseU<unsigned long, unsigned long long, (sizeof(unsigned long) > sizeof(wchar_t))>::type,
(sizeof(int) > sizeof(wchar_t))>::type,
std::is_signed<wchar_t>::value
>::type;
};
// Char16_t - int, unsigned int, long, unsigned long, long long, unsigned long long
// dependent on the amount of goats recently sacrificed
template <>
struct promote_me <char16_t> {
using type =
TifChooseU <
TifChooseU <int,
TifChooseU<long, long long, (sizeof(long) > sizeof(char16_t))>::type,
(sizeof(int) > sizeof(char16_t))>::type,
TifChooseU <unsigned int,
TifChooseU<unsigned long, unsigned long long, (sizeof(unsigned long) > sizeof(char16_t))>::type,
(sizeof(int) > sizeof(char16_t))>::type,
std::is_signed<char16_t>::value
>::type;
};
// Char32_t - int, unsigned int, long, unsigned long, long long, unsigned long long
// dependent on the amount of goats recently sacrificed
template <>
struct promote_me <char32_t> {
using type =
TifChooseU <
TifChooseU <int,
TifChooseU<long, long long, (sizeof(long) > sizeof(char32_t))>::type,
(sizeof(int) > sizeof(char32_t))>::type,
TifChooseU <unsigned int,
TifChooseU<unsigned long, unsigned long long, (sizeof(unsigned long) > sizeof(char32_t))>::type,
(sizeof(int) > sizeof(char32_t))>::type,
std::is_signed<char32_t>::value
>::type;
};
// Enums and Bitfields - maybe later ^^
// Bool - int
template <>
struct promote_me <bool> {
using type = int;
};
void foo(const char* fmt, ...) {
va_list va;
va_start(va, fmt);
unsigned short a = va_arg(va, promote_me<unsigned short>::type);
bool b = va_arg(va, promote_me<bool>::type);
char32_t c = va_arg(va, promote_me<char32_t>::type);
unsigned char d = va_arg(va, promote_me<unsigned char>::type);
}
int main() {
const char* fmt;
unsigned short a = 1;
bool b = true;
char32_t c = 'a';
unsigned char d = 'c';
foo(fmt, a, b, c, d);
}
Если есть однострочное решение, я сочту это самоубийством :).
Вероятно, я улучшу это с помощью шаблона fits<T, U>
, а также исправлю
неэлегантное повторение кода wchar_t
и char16_t
char32_t
.
person
ScarletAmaranth
schedule
07.12.2013
unsigned short
по умолчанию зависит от платформы. - person Kerrek SB   schedule 07.12.2013template <typename T> struct promote_me_smart { using type = decltype(+T()); };
это действительно работает? - person ScarletAmaranth   schedule 07.12.2013operator+
. - person   schedule 07.12.2013float
) и, возможно, использоватьstd::declval
, но большую часть тяжелой работы должен выполнять унарный плюс. (Конечно, он работает так, как задумано для указателей, указателей на функции и массивов.) - person Kerrek SB   schedule 07.12.2013std::underlying_type
спешит на помощь? - person Kerrek SB   schedule 07.12.2013