是否可以将带有字符串化运算符的宏转换为 constexpr?

Is it possible to convert a macro with stringizing operator to a constexpr?

本文关键字:转换 constexpr 运算符 字符串 是否      更新时间:2023-10-16

我编写了以下宏来模仿 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">

简而言之,并不像听起来那么容易。

问题:

是否可以将此宏名称转换为constexpr

(或者我应该坚持旧的#define

不,不可能在constexpr函数中获取C++对象的名称。constexpr函数仍然可以在运行时调用,而在运行时,没有这种反射的可能性。事实上,C++的反思总体上是极其有限的。如果没有宏,您的反射能力仅限于使用肮脏和不直观的模板技巧测试成员的存在和类型,但不会以字符串形式返回名称。还要注意的是,一旦将参数传递给像NAMEOF1这样的函数,该参数的名称将始终"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 + """";

但是,如果我的理解是正确的,表达式""""将被解析为两个空字符串文字(""""(,因为它们并排出现,所以由预处理器附加到单个空字符串文字中。因此,您可以将""""替换为""以达到相同的效果。但也许你想要别的东西?