我编写了以下宏来模仿C#的nameof
运算符,但使用的是C ++ / CLI:
#define nameof(x) (#x)
if (info == nullptr)
throw gcnew ArgumentNullException(nameof(info));
我已尝试将此宏转换为constexpr
:
这些都不正确,它们返回ToString
的内容:
template <typename T>
constexpr auto NAMEOF1(T value)
{
return """" + value + """";
}
template <typename T>
constexpr auto NAMEOF2(T value)
{
return System::String::Format("{0}", value);
}
第三次尝试,使用typeid
关键字:
template <typename T>
constexpr auto NAMEOF3(T value)
{
return gcnew System::String(typeid(value).name());
}
但是它失败,并出现以下错误:
错误C3185:'typeid':用于托管类型'T',请改用'T :: typeid'
简而言之,听起来并不容易。
问题:
是否可以将此nameof宏转换为constexpr
?
(或我应该坚持使用旧的#define
吗?]
否,无法通过constexpr
函数获得C ++中的对象名称。 constexpr
函数仍然可以在运行时被调用,并且在运行时,这种反射是不可能的。实际上,C ++中的反射通常非常有限。如果没有宏,则您的反射能力仅限于使用肮脏和不直观的模板技巧测试成员的存在和类型,但是没有任何方法可以将名称返回为字符串。还应注意,一旦将参数传递给NAMEOF1
之类的函数,该参数的名称将[[always为"value"
。无法查询调用方的范围以获取所传递的名称或表达式。
#define nameof(x) (#x)
当然,这也是一个非常有限的解决方案。这将简单地将表达式x
变成一个完整的字符串,并且没有像C#中的nameof
那样具有不同实体和作用域的概念。我说这来自非托管C ++背景。从收到的错误消息中可以明显看出,托管C ++对
typeid
产生了有趣的影响。也许更了解C ++ / CLI的人可以启发我或给出更好的答案。或者,如果这种null检查是常见的模式,则可以将其包装到更简洁的宏中。例如:
define THROW_IF_NULL(x) \ if ((x) == nullptr){ \ throw gcnew ArgumentNullException(#x); \ }
示例用法:
void process_info(Info* info){ THROW_IF_NULL(info) // --snip-- }
从另一方面来说,我不确定您希望这样做吗:
return """" + value + """";
但是如果我的理解是正确的,则表达式""""
将被解析为两个空字符串文字(""
,""
),由于它们并排出现,因此预处理器将它们附加到一个单个空字符串文字。因此,您可以将""""
替换为""
以达到相同的效果。但是也许您还想要其他东西?