我实际上有两个问题。
这是" if(ClassPtr1)&& (ClassPtr2)"检查它们是否为空的正确方法?
我想知道是否可以在多行宏中完全包含if else语句。我附上了示例代码。
#define MACRO_NAME(object,expression){\
Class1* ClassPtr1 = dynamic_cast<Class1*>(object);\
Class2* ClassPtr2 = ClassPtr1->SomeMethod();\
if (ClassPtr1) && (ClassPtr2)\
{\
try\
{\
//some code
}\
catch(...)\
{\
//some code
}\
}\
else\
return expression;\
}
答案 0 :(得分:3)
1:不。您在检查之前使用ClassPtr1
,如果它实际上为空,则为未定义的行为。您需要首先获取ClassPtr1
,然后检查它,然后使用它来获取ClassPtr2
,然后检查它。
2:是的,原则上这很好。宏是否是一个好主意是一个不同的问题。
答案 1 :(得分:0)
1:您可以使用c ++ 11关键字nullptr进行检查。
2:是的,你可以!
答案 2 :(得分:0)
是的,它有效。唯一的问题是你错过了if
强制性括号,因此它不会像扩展后那样进行编译。
此外,您必须在访问它们之前检查两个指针,否则您将得到未定义的行为,如@Sebastian Redl所指出的那样。
答案 3 :(得分:0)
语法不太正确;那将是if (ClassPtr1 && ClassPtr2)
(if
的条件必须括在括号中。)
是的,您可以将任意代码放入宏中。但是您通常应该将多语句宏包装到do { ::: } while (0)
构造中,因为它是唯一包含终止;
的构造。所以你改变了你的宏:
#define MACRO_NAME(object, expression) do { \
/*as before*/ \
} while (0)
如果没有这个,使用分号后跟宏不会属于您期望的位置。考虑一下:
if (someCondition)
MACRO_NAME(a, b);
else
doStuff();
您会收到语法错误,因为宏后的;
会终止整个if
,导致else
无法匹配。
附加说明:您应该在取消引用之前检查ClassPtr1
以获取ClassPtr2
。
答案 4 :(得分:0)
1)是的,如果修复括号并且在检查它是否为NULL之前不使用可能为NULL的指针,则可以这样做。
2)是的,预处理器给出了OK代码。
使用代码(您的代码有一些修复程序可以编译):
#include <exception>
#include <string>
#define MACRO_NAME(object,expression){\
Class1* ClassPtr1 = dynamic_cast<Class1*>(object);\
Class2* ClassPtr2 = ClassPtr1->SomeMethod();\
if ((ClassPtr1) && (ClassPtr2))\
{\
try\
{\
return expression;\
}\
catch(const std::exception& msg)\
{\
ClassPtr2->SomeOtherMethod(msg.what());\
return 3;\
}\
}\
else\
return expression;\
}
class Class2{public: int SomeOtherMethod(std::string a){return 0;}};
class Class1{public: Class2* SomeMethod(){return 0;}};
int main()
{
Class1* a;
MACRO_NAME(a,2);
}
正在运行
cpp macro.cpp | tail -7
将产生
class Class2{public: int SomeOtherMethod(std::string a){return 0;}};
class Class1{public: Class2* SomeMethod(){return 0;}};
int main()
{
Class1* a;
{ Class1* ClassPtr1 = dynamic_cast<Class1*>(a); Class2* ClassPtr2 = ClassPtr1->SomeMethod(); if ((ClassPtr1) && (ClassPtr2)) { try { return 2; } catch(const std::exception& msg) { ClassPtr2->SomeOtherMethod(msg.what()); return 3; } } else return 2;};
}
答案 5 :(得分:0)
具有控制结构(如循环或if / else)的多行宏是可能的。最佳实践(在避免之后;-))就是将所有内容包装在&#34; do {...} while(false)&#34;像这样:
#define MACRO_NAME(object,expression)\
do { if(...) { doSomething; } else { doSomethingElse; } } while(false)
do ... while循环在语法上与单个语句兼容,而不是普通块或if ... else。例如,它可以很好地与用户在其后面写的分号一起使用。您可以在if .. else:
中使用它if(cond) MACRO(); else exit();
不会根据你的建议进行编译,因为MACRO后面的分号会创建第二个空的语句,以便&#34; else&#34;晃来晃去。做...而不是这样。
答案 6 :(得分:0)
我实际上有两个问题。 这是&#34; if(ClassPtr1)&amp;&amp; (ClassPtr2)&#34;检查它们是否为空的正确方法?
是的,检查是正确的。宏虽然有一些问题(见下文)。
I want to know if it is possible to include an if else statement completely inside a multi-line macro. I have attached example code.
是。以下是您的宏的一些问题(以及为什么您不应该使用宏代替函数):
考虑这个客户端代码:
if(some_condition)
MACRO_NAME(MyObject, a+b);
评估结果为:
if(some_condition)
Class1* ClassPtr1 = dynamic_cast<Class1*>(object);
Class2* ClassPtr2 = ClassPtr1->SomeMethod();
// ...
这很可能不是你想要的(因为ClassPtr2声明会发出编译错误 - 在if块中本地定义了ClassPtr1。)
解决方案:
使用do {
和} while(false)
围绕宏中的代码。这将确保宏扩展为单个代码块。宏将起作用,但仍然会产生使用宏编写代码所固有的所有问题。
用引发异常的模板函数替换宏(这是正确的解决方案)。作为(非通用)经验法则,使用宏编写重复代码是API设计不完整的症状(就像使用dynamic_cast是不良类层次结构设计的症状一样)。