Стандартный способ получить 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)>)