Stringifying template arguments

前端 未结 8 1679
花落未央
花落未央 2020-12-04 17:00

Is it possible in C++ to stringify template arguments? I tried this:

#define STRINGIFY(x) #x

template 
struct Stringify
{
     Stringify()         


        
8条回答
  •  孤街浪徒
    2020-12-04 17:27

    Here’s what I do: I have a demangle() function (implemented on top of abi::__cxa_demangle() which I call with a couple of convenience template function overloads, nameof(), with either the type I want stringified or an instance of same.

    It’s fairly compact, so I’ll reproduce it here in all its glory. In demangle.hh we have:

    #pragma once
    #include 
    
    namespace terminator {
    
        /// actual function to demangle an allegedly mangled thing
        char const* demangle(char const* const symbol) noexcept;
    
        /// convenience function template to stringify a name of a type,
        /// either per an explicit specialization:
        ///     char const* mytypename = terminator::nameof();
        template 
        char const* nameof() {
            try {
                return demangle(typeid(NameType).name());
            } catch (std::bad_typeid const&) {
                return "";
            }
        }
    
        ///  … or as implied by an instance argument:
        ///     char const* myinstancetypename = terminator::nameof(someinstance);
        template 
        char const* nameof(ArgType argument) {
            try {
                return demangle(typeid(argument).name());
            } catch (std::bad_typeid const&) {
                return "";
            }
        }
    
    } /* namespace terminator */
    

    … And then in demangle.cpp:

    #include "demangle.hh"
    
    #include 
    #include 
    #include 
    #include 
    
    namespace terminator {
    
        namespace {
    
            /// define one singular, private, static std::mutex,
            /// to keep the demangler from reentering itself
            static std::mutex mangle_barrier;
    
            /// define a corresponding private and static std::unique_ptr,
            /// using a delete-expression to reclaim the memory malloc()'ed by
            /// abi::__cxa_demangle() upon its return.
            /// … we use clang pragmas to add flags locally for this to work:
            #pragma clang diagnostic push
            #pragma clang diagnostic ignored "-Wglobal-constructors"
            #pragma clang diagnostic ignored "-Wexit-time-destructors"
            std::unique_ptr demangled_name{ nullptr, std::free };
            #pragma clang diagnostic pop
    
        }
    
        char const* demangle(char const* const symbol) noexcept {
            if (!symbol) { return ""; }
            std::lock_guard lock(mangle_barrier);
            int status = -4;
            demangled_name.reset(
                abi::__cxa_demangle(symbol,
                                    demangled_name.get(),
                                    nullptr, &status));
            return ((status == 0) ? demangled_name.release() : symbol);
        }
    
    } /* namespace terminator */
    

    To use this, I think you’ll have to link to libc++ (or whatever your local equivalent is) to use abi::__cxa_demangle(). What may be suboptimal for the OP is the fact that this does the demangling and stringification at runtime. I’d personally love something constexpr-friendly in leu of this, but since I suffer from a severe macro-abuse allergy, I find this to be the least generally-unreasonable solution to this problem.

    (the terminator namespace is inconsequential – I use this code in a libunwind-based stacktracer called from termination handler – feel free to s///g that token)

提交回复
热议问题