2017-01-19 95 views
0

Давайте предположим, что у меня есть макрос так:static_cast <T> против Т (п) для основных типов

#define IS_SIGNED_B(T) (static_cast<T>(-1)<0) 

было бы хорошо, чтобы написать его как

#define IS_SIGNED_B(T) (T(-1)<0) 

Зная, что Т (должен) всегда будет фундаментальным типом. И различные другие случаи, когда мне нужно определенное значение, чтобы быть явно определенного типа.

Я знаю, что это может вызвать проблемы в ситуациях, таких как:

signed char(0); 

Но, зная, что я основные типы typedef'ed как:

typedef signed char Int8; 
Int8(0); 

Существуют ли какие-либо другие вопросы, другие, чем это? Может ли конструктор фундаментального типа считаться идентичным статическому литье?

EDIT: Я знаю о существовании std::numeric_limits и std::is_signed. Это был просто пример. Не настоящий случай. Приношу свои извинения за то, что не упоминал об этом.

+2

Лично я бы обошел все это и нас ['std :: numeric_limits :: is_signed'] (http://en.cppreference.com/w/cpp/types/numeric_limits/is_signed) – NathanOliver

+2

Зачем вам нужен макрос для этого, когда существует ['std :: is_signed'] (http://en.cppreference.com/w/cpp/types/is_signed)? – Borgleader

+0

У вас, похоже, создается впечатление, что 'T (-1)' вызывает конструктор 'T' для' T == int', однако это просто альтернативный синтаксис для c-стиля, который, вероятно, реализован как 'static_cast', поэтому не должно быть разницы. – nwp

ответ

3

Может ли конструктор фундаментального типа считаться идентичным статическому литу?

Фундаментальные типы не имеют конструкторов. Int8(0) - это явное преобразование типа и альтернативный синтаксис для (Int8)0. Это известно как C-стиль. Альтернативный синтаксис называется функциональным выражением.

Для фундаментальных интегральных типов приведение в стиле C эквивалентно static_cast. Но это вообще не эквивалентно. Если static_cast не доступен, он будет выполнять reinterpret_cast (или const_cast, или комбинацию const_cast, и одну из других команд).

Есть ли другие проблемы, кроме этого?

Я не совсем понимаю, какую проблему или проблемы вы представили, но да, у явного преобразования типов есть большие проблемы. Основная проблема заключается в том, что программисты не идеальны, и вы не можете предположить, что всегда остается T is (should) always be a fundamental type. Вы хотите, чтобы компилятор поймал такие ошибки. Сводка в стиле C скроет некоторые из ошибок, которые могут возникнуть у вас или ваших коллег, и замените сообщения об ошибках неопределенным поведением.

Возможно, в контексте вашего макроса существует небольшая опасность неопределенного поведения, но, как вы сказали, это был всего лишь пример. Хорошее эмпирическое правило: Предпочитайте использовать точный тип * _cast, который вы намереваетесь, вместо того, чтобы позволить C-style cast выбрать одно из заклинаний, которые могут быть не такими, какие вы планировали.

+0

Спасибо. Это все, что я хотел знать. Можно ли считать его статическим или литым. Меня это беспокоило какое-то время, и я догадываюсь, что забыл о тех случаях, когда мне нужно было четко понять это. Приношу свои извинения за неправильное задание вопроса. –

1

Первое, что вам нужно сделать, это остановить использование препроцессора C без необходимости.

Просто используйте std::is_signed.

В противном случае, что-то вроде:

template<class T> 
constexpr 
std::integral_constant<bool, 
    (static_cast<T>(-1)<0) 
> is_signed_b() { return {}; } 

который является промышленной версией сила макроса.

Он возвращает пустой класс, который имеет constexpr conversion-to-bool, значение которого является желаемым результатом. Его можно оценить во время компиляции (на самом деле, это трудно).


Но что не так с вашим макросом?

Во-первых, макрос следует читать:

#define IS_SIGNED_B(...) (static_cast<__VA_ARGS__>(-1)<0) 

потому что

IS_SIGNED_B(std::tuple_element_t<some_tuple, Is>)... 

перерывы Needlessly с вашей реализации.

Препроцессор C не понимает C++. Он не понимает, что , s больше не содержатся в () или {}.

Как указано, если T является двухсловным типом, ваш код прерывается.

Другая проблема заключается в том, что если вы ее подадите, то не является интегральным типом, могут произойти странные вещи. Стили C-стиля прочны и будут работать для типов указателей. Таким образом, вы получите значение типа указателя -1 с левой стороны. Справа вы получите 0, который неявно преобразуется в нулевое значение любого типа указателя. Затем все сравнивается. Этот параграф содержит все виды неопределенного поведения.

 Смежные вопросы

  • Нет связанных вопросов^_^