2015-06-05 1 views
15

Есть ли стандартный способ получить размер типа переменной, на которую будет распространяться переменная, когда передается как вариационный аргумент?Стандартный способ получить sizeof (продвигаемый (x))

auto x = ...; 
auto y = sizeof(promoted(x)); 

Результаты должны быть:

char -> sizeof(int) 
int -> sizeof(int) 
float -> sizeof(double) 
... 
+8

Что именно ваш случай использования для этого? Это интересная проблема, я просто не знаю, для чего вы решили. – Borgleader

+1

@Borgleader Я работаю над встроенным проектом (Cortex A5, и мы предпочли бы не превышать размер кода 256 тыс.). ОС имеет две функции (в широком смысле), реализованные в разных модулях: (1) printf (2) enqueue_stuff/dequeue_stuff. Позднее принимает переменное число uint32_t. Я хочу enqueue_stuff -> dequeue_stuff -> printf. –

ответ

17

Мы можем просто объявить перегружен promoted функции с соответствующими типами:

int promoted(char); 
int promoted(short); 
int promoted(int); 
long promoted(long); 
long long promoted(long long); 
double promoted(float); 
double promoted(double); 
long double promoted(long double); 

Обратите внимание, что функции не нуждаются в реализации, потому что мы никогда не на самом деле называть их.

Вот простой тестовый прогон, который печатает 1, 4 и 4, 8 на моей машине:

std::cout << sizeof('a') << '\n'; 
std::cout << sizeof(promoted('a')) << '\n'; 

std::cout << sizeof(3.14f) << '\n'; 
std::cout << sizeof(promoted(3.14f)) << '\n'; 
+0

О, и это еще не работает для неподписанных типов. http://coliru.stacked-crooked.com/a/3d85ccffcea22351) Tbh, мне очень не нравится идея делать это вручную. –

+0

Это скорее ручная работа, но простая, простая в использовании и работает как для интегральных, так и для плавающих даже без C++ 11. Включите неподписанные материалы для практического использования. –

19
auto s = sizeof(+x); 

должны сделать трюк для целых чисел.

+x использует унарный оператор +, который выполняет целочисленную рекламу, как и любой другой арифметический оператор.

Мне не известны никакие стандартные правила продвижения для float, которые будут применяться здесь (в смысле цельной рекламы), поскольку вы можете сделать арифметику с ними без продвижения. Если вы всегда хотите продвигать, по крайней мере double вы можете попробовать

auto s = sizeof(x + 0.); 

, а затем различать между плавающей точкой и целыми числами, прежде чем попасть туда.

Опять же, я не думаю, что вы можете обрабатывать целые числа и плавающие точки сразу из-за разных значений «продвижения», которые мы применяем здесь.

+0

Интересно. Можете ли вы рассказать о том, что именно происходит с '+ x', что позволяет этому работать? – CoryKramer

+0

Фокус в том, как вы получаете акции с плавающей запятой ('4.6') –

+0

@ShafikYaghmour Это лучшее, что я могу сделать. По крайней мере, можно использовать это. (Надеюсь, я понятия не имею, что на самом деле делает OP). –

13

Обобщая ответ Baum Массачусетский технологический институт Augen, вы могли бы написать шаблоны функций, как это:

template <typename T> 
auto promoted(T) 
    -> std::enable_if_t<std::is_integral<T>::value, decltype(+T{})>; 

template <typename T> 
auto promoted(T) 
    -> std::enable_if_t<std::is_floating_point<T>::value, decltype(T{}+0.)>; 

//usage 
sizeof(promoted(a)) 

Или версия используя черты типа:

template <typename T, typename = void> 
struct promoted; 

template <typename T> 
struct promoted<T, std::enable_if_t<std::is_integral<T>::value>> 
{ using type = decltype(+T{}); }; 

template <typename T> 
struct promoted<T, std::enable_if_t<std::is_floating_point<T>::value>> 
{ using type = decltype(T{} + 0.); }; 

template <typename T> 
using promoted_t = typename promoted<T>::type; 

//usage 
sizeof(promoted_t<decltype(a)>) 
+1

Могу я предложить 'template std :: integ_constant )> promotion_size (T const &) {return {}; } '. Затем мы получаем 'promotion_size ('a')' как константу времени компиляции '4'. – Yakk

+0

Классический ответ на C++. Красивый код притворяется ужасно уродливым. – PythonNut

+0

Мне нравится этот ответ, и мне кажется, что это путь, но, к сожалению, для меня нет C++ 11, поэтому нет ''. :-( –