1

Struct Name is used to convert type declaration into a string. When testing a logic error occurs, when the type declaration is a function type (or type of pointer function) and has a parameter type declaration of pointer function with qualification (const, volatile, const volatile). The qualifier is missing from pointer function type in the function parameter. For more details can see the code below:

#include <iostream>
#include <stack>
#include <string>
#include <typeinfo>

Forward declaration of template struct Name :

template<typename T>
struct Name;

Struct Parameter

To split parameters from declarator of function type.

template<typename... Targs>
struct Parameter
{
    static void ToString(std::string& str, bool first = true)
    {}
};

template<typename Targ, typename... Targs>
struct Parameter<Targ, Targs...>
{
    static void ToString(std::string& str, bool first = true)
    {
        if (!first)
            str += ", ";
        str += Name<Targ>::ToString();
        Parameter<Targs...>::ToString(str, false);
    }
};

Struct Declarator

To classify the type of declaration with partial template specialization.

template<typename T>
struct Declarator
{
    typedef T RemovedType;
    static void ToString(std::string& str, 
        std::stack<std::string>& ptr_str_stack)
    {}
};

template<typename T>
struct Declarator<T*>
{
    typedef typename Declarator<T>::RemovedType RemovedType;
    static void ToString(std::string& str, 
        std::stack<std::string>& ptr_str_stack)
    {
        ptr_str_stack.push("*");
        Declarator<T>::ToString(str, ptr_str_stack);
    }
};

template<typename T>
struct Declarator<T*const>
{
    typedef typename Declarator<T>::RemovedType RemovedType;
    static void ToString(std::string& str, 
        std::stack<std::string>& ptr_str_stack)
    {
        ptr_str_stack.push("*const");
        Declarator<T>::ToString(str, ptr_str_stack);
    }
};

template<typename T>
struct Declarator<T*volatile>
{
    typedef typename Declarator<T>::RemovedType RemovedType;
    static void ToString(std::string& str, 
        std::stack<std::string>& ptr_str_stack)
    {
        ptr_str_stack.push("*volatile");
        Declarator<T>::ToString(str, ptr_str_stack);
    }
};

template<typename T>
struct Declarator<T*const volatile>
{
    typedef typename Declarator<T>::RemovedType RemovedType;
    static void ToString(std::string& str, 
        std::stack<std::string>& ptr_str_stack)
    {
        ptr_str_stack.push("*const volatile");
        Declarator<T>::ToString(str, ptr_str_stack);
    }
};

template<typename T, typename... Targs>
struct Declarator<T(*)(Targs...)>
{
    typedef typename Declarator<T>::RemovedType RemovedType;
    static void ToString(std::string& str, 
        std::stack<std::string>& ptr_str_stack)
    {
        str += "(*";
        while(!ptr_str_stack.empty())
        {
            str += ptr_str_stack.top();
            ptr_str_stack.pop();
        }
        str += ")(";
        Parameter<Targs...>::ToString(str);
        str += ")";
    }
};

template<typename T, typename... Targs>
struct Declarator<T(*const)(Targs...)>
{
    typedef typename Declarator<T>::RemovedType RemovedType;
    static void ToString(std::string& str, 
        std::stack<std::string>& ptr_str_stack)
    {
        str += "(*const";
        while(!ptr_str_stack.empty())
        {
            str += ptr_str_stack.top();
            ptr_str_stack.pop();
        }
        str += ")(";
        Parameter<Targs...>::ToString(str);
        str += ")";
    }
};

template<typename T, typename... Targs>
struct Declarator<T(*volatile)(Targs...)>
{
    typedef typename Declarator<T>::RemovedType RemovedType;
    static void ToString(std::string& str, 
        std::stack<std::string>& ptr_str_stack)
    {
        str += "(*volatile";
        while(!ptr_str_stack.empty())
        {
            str += ptr_str_stack.top();
            ptr_str_stack.pop();
        }
        str += ")(";
        Parameter<Targs...>::ToString(str, true);
        str += ")";
    }
};

template<typename T, typename... Targs>
struct Declarator<T(*const volatile)(Targs...)>
{
    typedef typename Declarator<T>::RemovedType RemovedType;
    static void ToString(std::string& str, 
        std::stack<std::string>& ptr_str_stack)
    {
        str += "(*const volatile";
        while(!ptr_str_stack.empty())
        {
            str += ptr_str_stack.top();
            ptr_str_stack.pop();
        }
        str += ")(";
        Parameter<Targs...>::ToString(str, true);
        str += ")";
    }
};

Struct Type

To classify the type of name with explicit template specialization.

template<typename T>
struct Type
{
    static void ToString(std::string& str)
    {
        str += typeid(T).name();
    }
};

template<>
struct Type<int>
{
    static void ToString(std::string& str)
    {
        str += "int";
    }
};

Definition template struct Name

To convert type declaration into a string.

template<typename T>
struct Name
{
    static std::string ToString()
    {
        
        typedef typename Declarator<T>::RemovedType SimpleType;
        std::string str;
        std::string declarator_str;
        std::stack<std::string> declarator_ptr_str_stack;
        Type<SimpleType>::ToString(str);
        Declarator<T>::ToString(declarator_str, declarator_ptr_str_stack);
        while(!declarator_ptr_str_stack.empty())
        {
            str += declarator_ptr_str_stack.top();
            declarator_ptr_str_stack.pop();
        }
        str += declarator_str;
        return str;
    }
};

main test

int main()
{
    std::cout << Name<int(*)(int(*)())>::ToString() << std::endl;
    std::cout << Name<int(*const)(int(*const)())>::ToString() << std::endl;
    std::cout << Name<int(*volatile)(int(*const volatile)())>::ToString() << std::endl;
    std::cout << Name<int(*const volatile)(int(*volatile)())>::ToString() << std::endl;
}

Output(gcc):

int(*)(int(*)())
int(*const)(int(*)())
int(*volatile)(int(*)())
int(*const volatile)(int(*)())
Community
  • 1
  • 1
  • 3
    Top-level CV-qualifiers are dropped from parameter types for function arguments. I think that's what is happening here. – Mat Jul 09 '18 at 12:31
  • You might want to checkout what `boost::typeindex::type_id_with_cvr().prettyName()` does. – lubgr Jul 09 '18 at 12:39

0 Answers0