在编译时获取变量名的标准方法

Hum*_*awi 5 c++ compile-time c++11

在C++ 11或更高版本中是否有某种方法可以实现类似的行为:

int some_int;
std::string x=variable_name<some_int>::value; //Theoretical code 
std::cout << x;
Run Code Online (Sandbox Code Playgroud)

结果应该是:

some_int

如果没有,是否有编译器特定的方法来做到这一点?我的目标是MSVS.

Che*_*Alf 8

你问:

在C++ 11或更高版本中是否有某种方法可以实现类似的行为:

int some_int;
std::string x=type_name<some_int>::value; //Theoretical code 
std::cout << x;
Run Code Online (Sandbox Code Playgroud)

结果应该是:

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;
}
Run Code Online (Sandbox Code Playgroud)

如果你要求不同的东西,那么请发一个新问题,因为现在已经回答了这个问题(修改问题会使这个答案无效).


作为现实世界的使用示例,这里是将变量及其名称传递给测试函数的宏:

#define TEST( v ) test( v, #v )
Run Code Online (Sandbox Code Playgroud)

如果您希望编译时检查有问题的名称是变量或类型名称,那么您可以简单地应用sizeof,例如在逗号表达式中:

#define NAME_OF( v ) (sizeof(v), #v)
Run Code Online (Sandbox Code Playgroud)

有之间的差异sizeof或没有,这是否是保证在编译时做纯粹,对可能产生的代码也做在运行时的东西.

为避免可能的警告,您可以将伪转换添加到void:

#define NAME_OF( v ) ((void) sizeof(v), #v)
Run Code Online (Sandbox Code Playgroud)

为了使这项工作也适用于函数名称,您可以添加typeid:

#define NAME_OF( name ) ((void) sizeof(typeid(name)), #name)
Run Code Online (Sandbox Code Playgroud)

完整的例子:

#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;
}
Run Code Online (Sandbox Code Playgroud)

但是,检查不是100%完美,因为它仍然可以将函数调用传递给NAME_OF宏.

  • @LightnessRacesinOrbit:您的评论指出,这不是一个答案.相反,它究竟有什么要求.有关的目标不切实际的注释应该*下去的问题*,而不是在每个答案. (4认同)
  • @Niall:是的,我考虑过,但没有这样做,因为它当时不适用于类型名称。然而,这种思维方式(我所做的)是错误的;没有必要自动化一切。程序员当然知道代码是要处理变量名还是类型名,并且可以表达出来。 (2认同)

Ter*_*ass 6

正如其他人所指出的那样,您确实可以使用宏来"变换"变量名称.但是,#define NAMEOF(variable) #variable您可以使用以下定义,而不是简单地将其定义为:

#define NAMEOF(variable) ((decltype(&variable))nullptr, #variable)
Run Code Online (Sandbox Code Playgroud)

如您所见,它使用逗号运算符.这个表达式的左边部分只执行(无意义的)转换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
Run Code Online (Sandbox Code Playgroud)

因此,如果在将来的重构中你修改了value变量的名称,你也不会忘记修改使用其名称的地方,因为编译器会尖叫你,直到你也修复NAMEOF了这个变量的每个用法.

在MinGW-W64上测试(gcc v5.2.0)


在注释中,@iammilind@Niall提出了另外两种定义此宏的方法,它们不依赖于特定于C++ 11的decltype()运算符:

#define NAMEOF(variable) ((void*)&variable, #variable)
Run Code Online (Sandbox Code Playgroud)

...要么...

// 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
Run Code Online (Sandbox Code Playgroud)

@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!
Run Code Online (Sandbox Code Playgroud)


Leo*_*eon 5

注释中可以看出,您需要将变量的值及其名称传递给函数.这必须在宏的帮助下完成:

#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;
}
Run Code Online (Sandbox Code Playgroud)

输出:

i=123
d=45.67
s=qwerty
Run Code Online (Sandbox Code Playgroud)