在编译时获取变量名的标准方法
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;
结果应该是:
some_int
如果没有,是否有特定于编译器的方法?我的目标是 MSVS。
你问:
Is there some way in C++11 or higher to achieve a similar behavior to:
int some_int;
std::string x=type_name<some_int>::value; //Theoretical code
std::cout << x;
Result should be:
some_int
是的,您可以只使用预处理器的 字符串化运算符 #
:
#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;
}
如果您要求不同的东西,请post一个新问题,因为这个问题现在已经得到回答(修改问题会使这个答案无效)。
作为现实世界的示例用法,这里是将变量及其名称传递给测试函数的宏:
#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
宏。
如 所述,您需要它来将变量的值及其名称传递给函数。这必须借助宏来完成:
#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
正如其他人所指出的,您确实可以使用宏来 "stringify" 变量名。但是,与其简单地将其定义为 #define NAMEOF(variable) #variable
,您还可以使用以下定义:
#define NAMEOF(variable) ((decltype(&variable))nullptr, #variable)
如您所见,它使用了逗号运算符。该表达式的左侧部分除了执行从 nullptr
到指向 variable
类型的指针的(无意义的)转换外,什么都不做,其结果立即被丢弃。右边部分只是 returns 字符串化变量的名称。
为什么这比在宏中简单地使用 #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 v5.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!
在 C++11 或更高版本中是否有某种方法可以实现与以下类似的行为:
int some_int;
std::string x=variable_name<some_int>::value; //Theoretical code
std::cout << x;
结果应该是:
some_int
如果没有,是否有特定于编译器的方法?我的目标是 MSVS。
你问:
Is there some way in C++11 or higher to achieve a similar behavior to:
int some_int; std::string x=type_name<some_int>::value; //Theoretical code std::cout << x;
Result should be:
some_int
是的,您可以只使用预处理器的 字符串化运算符 #
:
#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;
}
如果您要求不同的东西,请post一个新问题,因为这个问题现在已经得到回答(修改问题会使这个答案无效)。
作为现实世界的示例用法,这里是将变量及其名称传递给测试函数的宏:
#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
宏。
如
#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
正如其他人所指出的,您确实可以使用宏来 "stringify" 变量名。但是,与其简单地将其定义为 #define NAMEOF(variable) #variable
,您还可以使用以下定义:
#define NAMEOF(variable) ((decltype(&variable))nullptr, #variable)
如您所见,它使用了逗号运算符。该表达式的左侧部分除了执行从 nullptr
到指向 variable
类型的指针的(无意义的)转换外,什么都不做,其结果立即被丢弃。右边部分只是 returns 字符串化变量的名称。
为什么这比在宏中简单地使用 #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 v5.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!