我会为此使用 SFINAE。首先,我们定义两个函数,它们返回错误消息的字符串:
namespace detail
{
// for messages with "details" member:
template<typename MsgType>
std::string makeMsgString(const MsgType& msg, decltype(MsgType::details)*)
{
return "Error: " + msg.error + ", details: " + msg.details;
}
// for messages without "details" member:
template<typename MsgType>
std::string makeMsgString(const MsgType& msg, ...)
{
return "Error: " + msg.error + ", no details";
}
}
现在,这些函数可以这样使用:
struct NonSpecificMsg { std::string error; };
struct SpecificMsg { std::string error, details; };
template<typename MsgType>
void reportErr(const MsgType& msg)
{
std::cout << detail::makeMsgString(msg, nullptr) << "\n";
}
int main()
{
reportErr(NonSpecificMsg { "some error" }); // 1
reportErr(SpecificMsg { "some other error", "some details" }); // 2
return 0;
}
这里会发生什么?
致电 1):NonSpecificMsg
没有details
成员,因此第一个重载不存在。自从MsgType::details
不存在,decltype(MsgType::details)*
不是有效类型。 SFINAE 会导致该定义被忽略,而不是在编译期间引发错误。
只有重载2),不访问details
member.
致电2):SpecificMsg
has details
,因此编译器会考虑这两个重载。但是,可变参数函数重载(第二个)的优先级始终低于任何其他匹配重载,因此选择第一个。
Edit:这是 C++11 解决方案。很遗憾,decltype
在 GCC 4.8 中引入。
Edit 2:事实证明decltype
can与 GCC 4.6 一起使用(它是在版本 4.3 中引入的)。版本 4.8.1 更改了其语义,但在 OP 的情况下,以前的版本将起作用 - 请参阅GCC 的 C++ 状态页面 https://gcc.gnu.org/projects/cxx-status.html