c++ - 是否可以将带有字符串化运算符的宏转换为 constexpr?
问题描述
我编写了以下宏来模仿 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宏转换为 a constexpr
?
(或者我应该坚持旧的#define
?)
解决方案
不,不可能在constexpr
函数中获取 C++ 中对象的名称。constexpr
函数仍然可以在运行时被调用,并且在运行时,这种反射是不可能的。实际上,一般 C++ 中的反射是极其有限的。如果没有宏,您的反射能力将仅限于使用肮脏和不直观的模板技巧来测试成员的存在和类型,但不会将名称作为字符串返回。另请注意,一旦将参数传递给类似的函数NAMEOF1
,该参数的名称将始终为"value"
. 无法查询调用者的范围以获取传递的名称或表达式。
你应该坚持你的解决方案:
#define nameof(x) (#x)
当然,这也是一个非常有限的解决方案。这将简单地将表达式x
完全逐字转换为字符串,并且没有nameof
C# 中不同实体和范围的概念。
我说这来自非托管 C++ 背景。从您收到的错误消息中,很明显托管 C++ 对typeid
. 也许对 C++/CLI 有更多了解的人可以启发我或给出更好的答案。
或者,如果这种空检查是一种常见的模式,您可以将其包装成一个更简洁的宏。例如:
define THROW_IF_NULL(x) \
if ((x) == nullptr){ \
throw gcnew ArgumentNullException(#x); \
}
示例用法:
void process_info(Info* info){
THROW_IF_NULL(info)
// --snip--
}
另一方面,我不确定您希望这样做:
return """" + value + """";
但如果我的理解是正确的,则表达式""""
将被解析为两个空字符串文字(""
, ""
),因为它们并排出现,所以预处理器将它们附加到单个空字符串文字中。因此,您可以替换""""
为""
以达到相同的效果。但也许你想要别的东西?
推荐阅读
- unit-testing - 带 xUnit 的 Moq 和 AutoMoq (AutoFixture) 的依赖注入
- python - 子进程如何决定将什么编码写入仅接受 str 的文件对象
- python - Python:如何从 Selenium 的下拉菜单中选择选项,隐藏元素
- javascript - 如何模拟在使用 Jest 测试的 React 组件中进行的 API 调用
- excel - 如何从 Excel vba 更改 Word 页脚的变量?
- ruby-on-rails - 在求和/添加其他值时按唯一值分组
- javascript - 如何在 JavaScript 中使用递归实现斐波那契数
- vim - 如何从linux服务器上vim打开的文件复制到我的windows记事本++
- bash - 为什么管道会截断内容,而重定向到/从中间文件不会?
- powershell - 如何让 Powershell 识别带有变音符号“ä”的文件名?