#c #templates #macros
#c #шаблоны #макросы
Вопрос:
Поскольку кто-то в нашей группе ненавидит исключения (давайте не будем обсуждать это здесь), мы склонны использовать макросы проверки ошибок в наших проектах на C . Я столкнулся со странным сбоем компиляции при использовании шаблонной функции с двумя параметрами типа. Есть несколько ошибок (ниже), но я думаю, что основной причиной является предупреждение:
warning C4002: too many actual parameters for macro 'BOOL_CHECK_BOOL_RETURN'
Вероятно, лучше всего объясняется в коде:
#include "stdafx.h"
template<class A, class B>
bool DoubleTemplated(B amp; value)
{
return true;
}
template<class A>
bool SingleTemplated(A amp; value)
{
return true;
}
bool NotTemplated(bool amp; value)
{
return true;
}
#define BOOL_CHECK_BOOL_RETURN(expr)
do
{
bool __b = (expr);
if (!__b)
{
return false;
}
} while (false)
bool call()
{
bool thing = true;
// BOOL_CHECK_BOOL_RETURN(DoubleTemplated<int, bool>(thing));
// Above line doesn't compile.
BOOL_CHECK_BOOL_RETURN((DoubleTemplated<int, bool>(thing)));
// Above line compiles just fine.
bool temp = DoubleTemplated<int, bool>(thing);
// Above line compiles just fine.
BOOL_CHECK_BOOL_RETURN(SingleTemplated<bool>(thing));
BOOL_CHECK_BOOL_RETURN(NotTemplated(thing));
return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
call();
return 0;
}
Вот ошибки, когда нарушающая строка не закомментирована:
1>------ Build started: Project: test, Configuration: Debug Win32 ------
1>Compiling...
1>test.cpp
1>c:junktemptesttesttest.cpp(38) : warning C4002: too many actual parameters for macro 'BOOL_CHECK_BOOL_RETURN'
1>c:junktemptesttesttest.cpp(38) : error C2143: syntax error : missing ',' before ')'
1>c:junktemptesttesttest.cpp(38) : error C2143: syntax error : missing ';' before '{'
1>c:junktemptesttesttest.cpp(41) : error C2143: syntax error : missing ';' before '{'
1>c:junktemptesttesttest.cpp(48) : error C2143: syntax error : missing ';' before '{'
1>c:junktemptesttesttest.cpp(49) : error C2143: syntax error : missing ';' before '{'
1>c:junktemptesttesttest.cpp(52) : error C2143: syntax error : missing ';' before '}'
1>c:junktemptesttesttest.cpp(54) : error C2065: 'argv' : undeclared identifier
1>c:junktemptesttesttest.cpp(54) : error C2059: syntax error : ']'
1>c:junktemptesttesttest.cpp(55) : error C2143: syntax error : missing ';' before '{'
1>c:junktemptesttesttest.cpp(58) : error C2143: syntax error : missing ';' before '}'
1>c:junktemptesttesttest.cpp(60) : error C2143: syntax error : missing ';' before '}'
1>c:junktemptesttesttest.cpp(60) : fatal error C1004: unexpected end-of-file found
1>Build log was saved at "file://c:junktemptesttestDebugBuildLog.htm"
1>test - 12 error(s), 1 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Есть идеи? Спасибо!
Комментарии:
1. Есть ли возможность застрелить этого определенного человека или, по крайней мере, обвинить его в романе с дочерью босса?
Ответ №1:
Препроцессор ничего не понимает в C ! Она просто выполняет лексические замены.
При объявлении макроса с несколькими аргументами аргументы разделяются запятой. Поскольку в вашем вызове макроса есть запятая, вы вызываете макрос с несколькими параметрами, несмотря на то, что было объявлено, что он принимает только один аргумент.
Круглые скобки понимаются PP как формирующие группу токенов, поэтому все, что находится внутри набора круглых скобок, представляет собой один большой токен.
Ответ №2:
Макросы не знают языка и работают только с лексическими маркерами. Аргументы для макроса разделяются запятой, поэтому следующий код пытается «вызвать» макрос с двумя аргументами:
BOOL_CHECK_BOOL_RETURN(DoubleTemplated<int, bool>(thing));
DoubleTemplated<int
и bool>(thing)
. Это предупреждение, которое вы видите, а также причина других ошибок. Ниже приведен правильный способ защиты от ,
в списке аргументов шаблона:
BOOL_CHECK_BOOL_RETURN((DoubleTemplated<int, bool>(thing)));
Ответ №3:
В строке, которая не компилируется, эта запятая интерпретируется препроцессором как разделитель аргументов макроса.
В стандарте C99 (у меня нет под рукой стандарта C , но он будет очень похож) мы видим следующее в разделе 6.10.3:
Последовательность токенов предварительной обработки, ограниченных наиболее совпадающими круглыми скобками, образует список аргументов для функционального макроса. Отдельные аргументы в списке разделены токенами предварительной обработки через запятую, но токены предварительной обработки через запятую между соответствующими внутренними скобками не разделяют аргументы.
Так вот почему работает ваш второй экземпляр макроса.