Search code examples
c++stringc++-cliconstexprpreprocessor-directive

Is it possible to convert a macro with stringizing operator to a constexpr?


I have written the following macro to mimic C#'s nameof operator but in C++/CLI:

#define nameof(x) (#x)

if (info == nullptr)
    throw gcnew ArgumentNullException(nameof(info));

I have tried to convert this macro to a constexpr:

Either of these are wrong, they return the content of 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);
}

Third attempt, using the typeid keyword:

template <typename T>
constexpr auto NAMEOF3(T value)
{
    return gcnew System::String(typeid(value).name());
}

But it fails with the following error:

error C3185: 'typeid': used on managed type 'T', use 'T::typeid' instead

In short, not as easy as it sounds.

Question:

Is it possible to convert this nameof macro to a constexpr ?

(or should I just stick to good old #define ?)


Solution

  • No, it is not possible to obtain the name of an object in C++ in a constexpr function. constexpr functions are still able to be called at runtime, and at runtime, there is no possibility for this kind of reflection. Indeed, reflection in C++ in general is extremely limited. Without macros, your reflection abilities are limited to testing for the existence of and type of members using dirty and unintuitive template trickery, but nothing that returns a name as a string. Also be aware that as soon as an argument is passed to a function like NAMEOF1, the name of that argument will always be "value". There is no way to query the scope of the caller for the name or expression that was passed.

    You should stick with your solution:

    #define nameof(x) (#x)
    

    This is of course, also a very limiting solution. This will simply turn the expression x into a string perfectly verbatim, and has no concept of different entities and scoping like nameof in C#.

    I say this coming from a non-managed C++ background. From the error message you receive, it's clear that managed C++ has interesting effects on typeid. Perhaps somebody who knows more about C++/CLI can enlighten me or give a better answer.

    Alternatively, if this sort of null-check is a frequent pattern, you could wrap that into a more concise macro. For example:

    define THROW_IF_NULL(x) \
        if ((x) == nullptr){ \
            throw gcnew ArgumentNullException(#x); \
        }
    

    Example usage:

    void process_info(Info* info){
        THROW_IF_NULL(info)
        // --snip--
    }
    


    On a side not, I'm not sure what you expect this to do:

    return """" + value + """";
    

    but if my understanding is correct, the expression """" will be parsed as two empty string literals ("", ""), which, because they appear side-by-side, are appended by the preprocessor into a single empty string literal. You can thus replace """" with "" to achieve the same effect. But perhaps you wanted something else?