A standard way for getting variable name at compile time

后端 未结 3 761
情话喂你
情话喂你 2021-02-15 14:13

Is there some way in C++11 or higher to achieve a similar behavior to:

int some_int;
std::string x=variable_name::value; //Theoretical code 
std:         


        
3条回答
  •  执念已碎
    2021-02-15 15:09

    As others have pointed out, you can indeed use a macro to "stringify" the variable name. However, instead of simply defining it as #define NAMEOF(variable) #variable, you can use the following definition:

    #define NAMEOF(variable) ((decltype(&variable))nullptr, #variable)
    

    As you can see, it uses a comma operator. The left part of this expression does nothing but performs a (pointless) conversion from nullptr to a pointer to variable's type, the result of which gets immediately discarded. The right part simply returns the stringified variable's name.

    Why is this better than simply using #variable in the macro?

    Thanks to the decltype() operator, the whole thing will only compile if you pass a variable of some sort and not some arbitrary string or a literal to NAMEOF macro. Consider the following example:

    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
    

    Because of this, if during future refactoring you modify the name of value variable, you won't forget to also modify places, where you use its name, since compiler will scream at you, until you also fix every usage of NAMEOF for this variable.

    Tested on MinGW-W64 (gcc v5.2.0)


    In the comments, @iammilind and @Niall have suggested two other ways to define this macro, which don't rely on C++11-specific decltype() operator:

    #define NAMEOF(variable) ((void*)&variable, #variable)
    

    ...or...

    // 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
    

    Using such a macro with @Leon's suggestion, based on your comments, we get:

    template
    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!
    

提交回复
热议问题