在编译时获取变量名的标准方法
A standard way for getting variable name at compile time
在C++11或更高版本中是否有某种方法可以实现与类似的行为
int some_int;
std::string x=variable_name<some_int>::value; //Theoretical code
std::cout << x;
结果应该是:
某些
如果没有,是否有编译器特定的方法可以做到这一点?我的目标是MSVS。
您询问:
在C++11或更高版本中,是否有某种方法可以实现与类似的行为
int some_int; std::string x=type_name<some_int>::value; //Theoretical code std::cout << x;
结果应该是:
某些
是的,您只需使用预处理器的字符串运算符#
:
#include <iostream>
#define NAME_OF( v ) #v
using namespace std;
auto main() -> int
{
int some_int;
//std::string x=type_name<some_int>::value; //Theoretical code
auto x = NAME_OF( some_int );
(void) some_int;
cout << x << endl;
}
如果你想问一些不同的问题,那么请发布一个新问题,因为这个问题现在已经得到了回答(修改问题会使这个答案无效)。
作为真实世界用法的一个示例,这里的宏将变量及其名称传递给测试函数:
#define TEST( v ) test( v, #v )
如果您想要编译时检查有问题的名称是变量或类型名称,那么您可以简单地应用sizeof
,例如在逗号表达式中:
#define NAME_OF( v ) (sizeof(v), #v)
有没有sizeof
的区别在于,这是否保证完全在编译时完成,而不是可能在运行时生成代码来做一些事情。
为了避免可能的警告,您可以在void
:中添加伪转换
#define NAME_OF( v ) ((void) sizeof(v), #v)
为了使这也适用于函数名,您可以添加一个typeid
:
#define NAME_OF( name ) ((void) sizeof(typeid(name)), #name)
完整示例:
#include <typeinfo>
#define NAME_OF( name ) ((void) sizeof(typeid(name)), #name)
void foo() {}
#include <iostream>
using namespace std;
auto main() -> int
{
int some_int;
(void) some_int;
//std::string x=type_name<some_int>::value; //Theoretical code
auto v = NAME_OF( some_int );
auto t = NAME_OF( int );
auto f = NAME_OF( foo );
#ifdef TEST_CHECKING
(void) NAME_OF( not_defined );
#endif
cout << v << ' ' << t << ' ' << f << endl;
}
不过,检查并不是100%完美,因为仍然可以将函数调用传递给NAME_OF
宏。
#define NAMEOF(variable) #variable
:
#define NAMEOF(variable) ((decltype(&variable))nullptr, #variable)
正如您所看到的,它使用了逗号运算符。这个表达式的左边部分什么也不做,只是执行从nullptr
到指向variable
类型的指针的(毫无意义的)转换,转换结果会立即被丢弃。右边的部分只是返回字符串化变量的名称。
为什么这比在宏中简单地使用#variable
要好
多亏了decltype()
运算符,只有当您向NAMEOF
宏传递某种类型的变量而不是任意字符串或文字时,整个过程才会编译。考虑以下示例:
double value = 523231231312.0095;
cout<< NAMEOF(value) << endl; // value
cout<< NAMEOF(value1) << endl; // Compiler error: 'value1' was not declared in this scope
cout<< NAMEOF(42) << endl; // Compiler error: lvalue required as unary '&' operand
因此,如果在未来的重构过程中修改value
变量的名称,您不会忘记修改使用其名称的位置,因为编译器会对您大喊大叫,直到您修复该变量的NAMEOF
的每次使用。
在MinGW-W64(gcc v.2.0)上测试
在评论中,@iammilind
和@Niall
提出了另外两种定义该宏的方法,它们不依赖于C++11特定的decltype()
运算符:
#define NAMEOF(variable) ((void*)&variable, #variable)
或
// Unlike other definitions, this one, suggested by @Niall,
// won't get broken even if unary & operator for variable's type
// gets overloaded in an incompatible manner.
#define NAMEOF(variable) ((void)variable, #variable)
// On the other hand, it accepts literals as parameters for NAMEOF,
// though this might be desired behaviour, depending on your requirements.
NAMEOF(42); // 42
在@Leon
的建议下使用这样一个宏,根据您的评论,我们得到:
template<class T>
void foo(T var, const char* varname)
{
std::cout << varname << "=" << var << std::endl;
}
#define FOO(var) foo(var, NAMEOF(var))
int someVariable = 5;
FOO(someVariable); // someVariable = 5
FOO(nonExistingVariable); // compiler error!
根据注释,您需要它来将变量的值及其名称传递到函数中。这必须在宏的帮助下完成:
#include <iostream>
template<class T>
void foo(T var, const char* varname)
{
std::cout << varname << "=" << var << std::endl;
}
#define FOO(var) foo(var, #var)
int main()
{
int i = 123;
double d = 45.67;
std::string s = "qwerty";
FOO(i);
FOO(d);
FOO(s);
return 0;
}
输出:
i=123
d=45.67
s=qwerty
- 没有取消引用/解包对象的标准方法?
- 是否有一种标准方法来计算两个 asctime() 值之间的天数
- 导入模块的标准方法
- 有没有一种标准方法可以在C++中获取第 n 个"下一个"浮点值
- C++ 捕获异常后进行清理的标准方法是什么?
- memcpy 是将浮子打包到 uint32 中的标准方法吗?
- 读取二进制文件的惯用C++17标准方法是什么
- 在 c++ 中创建 dll 并在 delphi 中调用的标准方法
- 在 NTL 中构造多项式的标准方法是什么?
- C 是否具有对两个STD :: sets,vectors等进行三角比较的标准方法
- 获取非专用标准::矢量容器的标准方法<bool>
- 将结构传递到头文件的标准方法
- C 11中的标准方法是什么,可以访问std :: vector中元素n的指针
- 组合来自多个线程的数据的标准方法?
- 标准::字符串::空的未定义符号错误;Mac OS High Sierra 上的 c++ 标准方法链接错误
- 在C++中初始化布尔向量的标准方法是什么
- 在C 中对二进制对象进行编码/解码的标准方法
- 有没有一种标准方法来确保一段代码在全局范围内执行
- 处理对存储在私有映射中的值的封装访问的标准方法,而不破坏C++中的抽象
- 是否有一种替换C风格的Bool数组的标准方法