Стандартный способ получить sizeof (повышается (x))

Существует ли стандартный способ получить размер типа, к которому будет распространяться переменная, когда передается как переменный аргумент?

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

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

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

Ответы

Ответ 1

Мы можем просто объявить перегруженные функции 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';

Ответ 2

auto s = sizeof(+x);

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

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

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

auto s = sizeof(x + 0.);

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

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

Ответ 3

Чтобы обобщить ответ Baum mit 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)>)