Dynamic_cast в assert Причинить ошибку

Я использую устаревшую 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 -statement в assert: assert(dynamic_cast<Foo<pair<int, int>>*>(test) != NULL), я получаю сообщение об ошибке:

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

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

Ответ 1

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

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

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

dynamic_cast<Foo<pair<int

и

int>>*>(test) != NULL

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

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

Ответ 2

Yup: макросы обрабатывают запятые верхнего уровня как разделители аргументов. Самое простое исправление - поместить круглые скобки вокруг нарушающего кода:

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

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

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

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