dynamic_cast в утверждении, вызывающем ошибку

Я использую устаревшую Visual Studio 2008 (позвольте мне избавить вас от проблем "вот ваша проблема".) Это похоже на проблему с Visual Studio: http://rextester.com/XKFR77690 Похоже, это проблема с макросом assert: http://ideone.com/bhxMi0

Учитывая эти структуры:

struct base { virtual ~base() {} };

template <typename T>
struct Foo : base { T foo; };

Я могу сделать это:

base* test = new Foo<pair<int, int>>;

if(dynamic_cast<Foo<pair<int, int>>*>(test) != NULL) cout << "hello world\n";

Но когда я использую тот же самый код, что и в операторе if в assert: assert(dynamic_cast<Foo<pair<int, int>>*>(test) != NULL), я получаю сообщение об ошибке:

предупреждение C4002: слишком много фактических параметров для макроса assert
ошибка C2143: синтаксическая ошибка: отсутствует ',' перед ')'

Кстати, я могу исправить это, используя приведение в стиле C: assert((Foo<pair<int, int>>*)(test) != NULL) Но я думаю, что приведение в стиле C сделает static_cast, а не dynamic_cast, чего я не хочу.


person Jonathan Mee    schedule 02.11.2016    source источник


Ответы (2)


assert — это макрос. Он обрабатывается препроцессором, который ничего не знает о конструкциях C++. Итак, следующее:

assert(dynamic_cast<Foo<pair<int, int>>*>(test) != NULL)

расширяется до макроса, похожего на функцию, с двумя аргументами, которые в данном случае таковы:

dynamic_cast<Foo<pair<int

а также

int>>*>(test) != NULL

Помните, что аргументы макроса, подобные функциям, разделяются запятыми. Это все, что видит препроцессор. Таким образом, в этом случае он видит 2 аргумента вместо 1 аргумента, требуемого assert.

Ваша версия приведения в стиле C работает случайно из-за круглых скобок, которые имеют более высокий приоритет, чем запятая. Размещение их вокруг dynamic_cast также делает свою работу.

person DeiDei    schedule 02.11.2016
comment
Re: ответ ниже меня - SO переставляет ответы в зависимости от различных факторов, поэтому ниже и выше могут меняться. Прямо сейчас, например, я не вижу ни одного ответа под вашим, но я вижу один над ним. - person Pete Becker; 02.11.2016
comment
@PeteBecker Я потратил 20 секунд на поиск нужного слова, и ниже был моим последним средством... - person DeiDei; 02.11.2016
comment
@DeiDei Просто свяжите ответ. - person Jonathan Mee; 02.11.2016

Ага: макросы обрабатывают запятые верхнего уровня как разделители аргументов. Самое простое исправление — заключить в круглые скобки неверный код:

assert((dynamic_cast<Foo<pair<int, int>>*>(test)) != NULL)

или, если хотите, круглые скобки вокруг всего содержимого:

assert((dynamic_cast<Foo<pair<int, int>>*>(test) != NULL))

Причина компиляции приведения в стиле C в вопросе заключается не в том, что это приведение в стиле C, а в том, что код шаблона помещается в круглые скобки, поэтому запятая больше не находится на самом внешнем уровне.

person Pete Becker    schedule 02.11.2016