例如:

int a = 12;
cout << typeof(a) << endl;

预期的输出:

int

当前回答

一个没有函数重载的更通用的解决方案:

template<typename T>
std::string TypeOf(T){
    std::string Type="unknown";
    if(std::is_same<T,int>::value) Type="int";
    if(std::is_same<T,std::string>::value) Type="String";
    if(std::is_same<T,MyClass>::value) Type="MyClass";

    return Type;}

这里的MyClass是用户定义的类。这里还可以添加更多的条件。

例子:

#include <iostream>



class MyClass{};


template<typename T>
std::string TypeOf(T){
    std::string Type="unknown";
    if(std::is_same<T,int>::value) Type="int";
    if(std::is_same<T,std::string>::value) Type="String";
    if(std::is_same<T,MyClass>::value) Type="MyClass";
    return Type;}


int main(){;
    int a=0;
    std::string s="";
    MyClass my;
    std::cout<<TypeOf(a)<<std::endl;
    std::cout<<TypeOf(s)<<std::endl;
    std::cout<<TypeOf(my)<<std::endl;

    return 0;}

输出:

int
String
MyClass

其他回答

#include <iostream>
#include <typeinfo>
using namespace std;
#define show_type_name(_t) \
    system(("echo " + string(typeid(_t).name()) + " | c++filt -t").c_str())

int main() {
    auto a = {"one", "two", "three"};
    cout << "Type of a: " << typeid(a).name() << endl;
    cout << "Real type of a:\n";
    show_type_name(a);
    for (auto s : a) {
        if (string(s) == "one") {
            cout << "Type of s: " << typeid(s).name() << endl;
            cout << "Real type of s:\n";
            show_type_name(s);
        }
        cout << s << endl;
    }

    int i = 5;
    cout << "Type of i: " << typeid(i).name() << endl;
    cout << "Real type of i:\n";
    show_type_name(i);
    return 0;
}

输出:

Type of a: St16initializer_listIPKcE
Real type of a:
std::initializer_list<char const*>
Type of s: PKc
Real type of s:
char const*
one
two
three
Type of i: i
Real type of i:
int

你可以上特质课。喜欢的东西:

#include <iostream>
using namespace std;

template <typename T> class type_name {
public:
    static const char *name;
};

#define DECLARE_TYPE_NAME(x) template<> const char *type_name<x>::name = #x;
#define GET_TYPE_NAME(x) (type_name<typeof(x)>::name)

DECLARE_TYPE_NAME(int);

int main()
{
    int a = 12;
    cout << GET_TYPE_NAME(a) << endl;
}

DECLARE_TYPE_NAME定义的存在是为了让您更容易地为所有需要的类型声明这个trait类。

这可能比涉及typeid的解决方案更有用,因为您可以控制输出。例如,在我的编译器上使用typeid For long long会给出“x”。

对于一些不同的东西,这里有一个类型的“To English”转换,解构每个限定符、范围、参数等等,递归地构建描述类型的字符串,我认为“演绎这个”建议将有助于减少许多特殊化。无论如何,这是一个有趣的晨练,尽管过度膨胀。:)

struct X {
    using T = int *((*)[10]);
    T f(T, const unsigned long long * volatile * );
};

int main() {

    std::cout << describe<decltype(&X::f)>() << std::endl;
}

输出:

pointer to member function of class 1X taking (pointer to array[10]
of pointer to int, pointer to volatile pointer to const unsigned 
long long), and returning pointer to array[10] of pointer to int

代码如下: https://godbolt.org/z/7jKK4or43

注:最新版本在我的github: https://github.com/cuzdav/type_to_string

// Print types as strings, including functions, member 

#include <type_traits>
#include <typeinfo>
#include <string>
#include <utility>

namespace detail {

template <typename T> struct Describe;

template <typename T, class ClassT> 
struct Describe<T (ClassT::*)>  {
    static std::string describe();
};
template <typename RetT, typename... ArgsT> 
struct Describe<RetT(ArgsT...)>  {
    static std::string describe();
};
template <typename RetT, class ClassT, typename... ArgsT> 
struct Describe<RetT(ClassT::*)(ArgsT...)>  {
    static std::string describe();
};
template <typename RetT, class ClassT, typename... ArgsT> 
struct Describe<RetT(ClassT::*)(ArgsT...) const>  {
    static std::string describe();
};
template <typename RetT, class ClassT, typename... ArgsT> 
struct Describe<RetT(ClassT::*)(ArgsT...) volatile>  {
    static std::string describe();
};
template <typename RetT, class ClassT, typename... ArgsT> 
struct Describe<RetT(ClassT::*)(ArgsT...) noexcept>  {
    static std::string describe();
};
template <typename RetT, class ClassT, typename... ArgsT> 
struct Describe<RetT(ClassT::*)(ArgsT...) const volatile>  {
    static std::string describe();
};
template <typename RetT, class ClassT, typename... ArgsT> 
struct Describe<RetT(ClassT::*)(ArgsT...) const noexcept>  {
    static std::string describe();
};
template <typename RetT, class ClassT, typename... ArgsT> 
struct Describe<RetT(ClassT::*)(ArgsT...) volatile noexcept>  {
    static std::string describe();
};
template <typename RetT, class ClassT, typename... ArgsT> 
struct Describe<RetT(ClassT::*)(ArgsT...) const volatile noexcept>  {
    static std::string describe();
};
template <typename RetT, class ClassT, typename... ArgsT> 
struct Describe<RetT(ClassT::*)(ArgsT...)&>  {
    static std::string describe();
};
template <typename RetT, class ClassT, typename... ArgsT> 
struct Describe<RetT(ClassT::*)(ArgsT...) const &>  {
    static std::string describe();
};
template <typename RetT, class ClassT, typename... ArgsT> 
struct Describe<RetT(ClassT::*)(ArgsT...) volatile &>  {
    static std::string describe();
};
template <typename RetT, class ClassT, typename... ArgsT> 
struct Describe<RetT(ClassT::*)(ArgsT...) & noexcept>  {
    static std::string describe();
};
template <typename RetT, class ClassT, typename... ArgsT> 
struct Describe<RetT(ClassT::*)(ArgsT...) const volatile &>  {
    static std::string describe();
};
template <typename RetT, class ClassT, typename... ArgsT> 
struct Describe<RetT(ClassT::*)(ArgsT...) const & noexcept>  {
    static std::string describe();
};
template <typename RetT, class ClassT, typename... ArgsT> 
struct Describe<RetT(ClassT::*)(ArgsT...) volatile & noexcept>  {
    static std::string describe();
};
template <typename RetT, class ClassT, typename... ArgsT> 
struct Describe<RetT(ClassT::*)(ArgsT...) const volatile & noexcept>  {
    static std::string describe();
};
template <typename RetT, class ClassT, typename... ArgsT> 
struct Describe<RetT(ClassT::*)(ArgsT...) &&>  {
    static std::string describe();
};
template <typename RetT, class ClassT, typename... ArgsT> 
struct Describe<RetT(ClassT::*)(ArgsT...) const &&>  {
    static std::string describe();
};
template <typename RetT, class ClassT, typename... ArgsT> 
struct Describe<RetT(ClassT::*)(ArgsT...) volatile &&>  {
    static std::string describe();
};
template <typename RetT, class ClassT, typename... ArgsT> 
struct Describe<RetT(ClassT::*)(ArgsT...) && noexcept>  {
    static std::string describe();
};
template <typename RetT, class ClassT, typename... ArgsT> 
struct Describe<RetT(ClassT::*)(ArgsT...) const volatile &&>  {
    static std::string describe();
};
template <typename RetT, class ClassT, typename... ArgsT> 
struct Describe<RetT(ClassT::*)(ArgsT...) const && noexcept>  {
    static std::string describe();
};
template <typename RetT, class ClassT, typename... ArgsT> 
struct Describe<RetT(ClassT::*)(ArgsT...) volatile && noexcept>  {
    static std::string describe();
};
template <typename RetT, class ClassT, typename... ArgsT> 
struct Describe<RetT(ClassT::*)(ArgsT...) const volatile && noexcept>  {
    static std::string describe();
};

template <typename T>
std::string describe()
{
    using namespace std::string_literals;
    auto terminal = [&](char const * desc) {
        return desc + " "s + typeid(T).name();
    };
    if constexpr(std::is_const_v<T>) {
        return "const " + describe<std::remove_const_t<T>>();
    }
    else if constexpr(std::is_volatile_v<T>) {
        return "volatile " + describe<std::remove_volatile_t<T>>();
    }
    else if constexpr (std::is_same_v<bool, T>) {
        return "bool";
    }
    else if constexpr(std::is_same_v<char, T>) {
        return "char";
    }
    else if constexpr(std::is_same_v<signed char, T>) {
        return "signed char";
    }
    else if constexpr(std::is_same_v<unsigned char, T>) {
        return "unsigned char";
    }
    else if constexpr(std::is_unsigned_v<T>) {
        return "unsigned " + describe<std::make_signed_t<T>>();
    }
    else if constexpr(std::is_void_v<T>) {
        return "void";
    }
    else if constexpr(std::is_integral_v<T>) {
        if constexpr(std::is_same_v<short, T>) 
            return "short";
        else if constexpr(std::is_same_v<int, T>) 
            return "int";
        else if constexpr(std::is_same_v<long, T>) 
            return "long";
        else if constexpr(std::is_same_v<long long, T>) 
            return "long long";
    }
    else if constexpr(std::is_same_v<float, T>) {
        return "float";
    }
    else if constexpr(std::is_same_v<double, T>) {
        return "double";
    }
    else if constexpr(std::is_same_v<long double, T>) {
        return "long double";
    }
    else if constexpr(std::is_same_v<std::nullptr_t, T>) { 
        return "nullptr_t";
    }
    else if constexpr(std::is_class_v<T>) {
        return terminal("class");
    }
    else if constexpr(std::is_union_v<T>) {
        return terminal("union");
    }
    else if constexpr(std::is_enum_v<T>) {
        std::string result;
        if (!std::is_convertible_v<T, std::underlying_type_t<T>>) {
            result += "scoped ";
        }
        return result + terminal("enum");
    }  
    else if constexpr(std::is_pointer_v<T>) {
        return "pointer to " + describe<std::remove_pointer_t<T>>();
    }
    else if constexpr(std::is_lvalue_reference_v<T>) {
        return "lvalue-ref to " + describe<std::remove_reference_t<T>>();
    }
    else if constexpr(std::is_rvalue_reference_v<T>) {
        return "rvalue-ref to " + describe<std::remove_reference_t<T>>();
    }
    else if constexpr(std::is_bounded_array_v<T>) {
        return "array[" + std::to_string(std::extent_v<T>) + "] of " +
            describe<std::remove_extent_t<T>>();
    }
    else if constexpr(std::is_unbounded_array_v<T>) {
        return "array[] of " + describe<std::remove_extent_t<T>>();
    }
    else if constexpr(std::is_function_v<T>) {
        return Describe<T>::describe();
    }
    else if constexpr(std::is_member_object_pointer_v<T>) {
        return Describe<T>::describe();
    }
    else if constexpr(std::is_member_function_pointer_v<T>) {
        return Describe<T>::describe();
    }
}

template <typename RetT, typename... ArgsT> 
std::string Describe<RetT(ArgsT...)>::describe() {
    std::string result = "function taking (";
    ((result += detail::describe<ArgsT>(", ")), ...);
    return result + "), returning " + detail::describe<RetT>();
}

template <typename T, class ClassT> 
std::string Describe<T (ClassT::*)>::describe() {
    return "pointer to member of " + detail::describe<ClassT>() +
        " of type " + detail::describe<T>();
}

struct Comma {
    char const * sep = "";
    std::string operator()(std::string const& str) {
        return std::exchange(sep, ", ") + str;
    }
};
enum Qualifiers {NONE=0, CONST=1, VOLATILE=2, NOEXCEPT=4, LVREF=8, RVREF=16};

template <typename RetT, typename ClassT, typename... ArgsT>
std::string describeMemberPointer(Qualifiers q) {
    std::string result = "pointer to ";
    if (NONE != (q & CONST)) result += "const ";
    if (NONE != (q & VOLATILE)) result += "volatile ";
    if (NONE != (q & NOEXCEPT)) result += "noexcept ";
    if (NONE != (q & LVREF)) result += "lvalue-ref ";
    if (NONE != (q & RVREF)) result += "rvalue-ref ";
    result += "member function of " + detail::describe<ClassT>() + " taking (";
    Comma comma;
    ((result += comma(detail::describe<ArgsT>())), ...);
    return result + "), and returning " + detail::describe<RetT>();
}

template <typename RetT, class ClassT, typename... ArgsT> 
std::string Describe<RetT(ClassT::*)(ArgsT...)>::describe() {
    return describeMemberPointer<RetT, ClassT, ArgsT...>(NONE);
}
template <typename RetT, class ClassT, typename... ArgsT> 
std::string Describe<RetT(ClassT::*)(ArgsT...) const>::describe() {
    return describeMemberPointer<RetT, ClassT, ArgsT...>(CONST);
}
template <typename RetT, class ClassT, typename... ArgsT> 
std::string Describe<RetT(ClassT::*)(ArgsT...) noexcept>::describe() {
    return describeMemberPointer<RetT, ClassT, ArgsT...>(NOEXCEPT);
}
template <typename RetT, class ClassT, typename... ArgsT> 
std::string Describe<RetT(ClassT::*)(ArgsT...) volatile>::describe() {
    return describeMemberPointer<RetT, ClassT, ArgsT...>(VOLATILE);
}
template <typename RetT, class ClassT, typename... ArgsT> 
std::string Describe<RetT(ClassT::*)(ArgsT...) volatile noexcept>::describe() {
    return describeMemberPointer<RetT, ClassT, ArgsT...>(VOLATILE | NOEXCEPT);
}
template <typename RetT, class ClassT, typename... ArgsT> 
std::string Describe<RetT(ClassT::*)(ArgsT...) const volatile>::describe() {
    return describeMemberPointer<RetT, ClassT, ArgsT...>(CONST | VOLATILE);
}
template <typename RetT, class ClassT, typename... ArgsT> 
std::string Describe<RetT(ClassT::*)(ArgsT...) const noexcept>::describe() {
    return describeMemberPointer<RetT, ClassT, ArgsT...>(CONST | NOEXCEPT);
}
template <typename RetT, class ClassT, typename... ArgsT> 
std::string Describe<RetT(ClassT::*)(ArgsT...) const volatile noexcept>::describe() {
    return describeMemberPointer<RetT, ClassT, ArgsT...>(CONST | VOLATILE | NOEXCEPT);
}

template <typename RetT, class ClassT, typename... ArgsT> 
std::string Describe<RetT(ClassT::*)(ArgsT...) &>::describe() {
    return describeMemberPointer<RetT, ClassT, ArgsT...>(LVREF);
}
template <typename RetT, class ClassT, typename... ArgsT> 
std::string Describe<RetT(ClassT::*)(ArgsT...) const &>::describe() {
    return describeMemberPointer<RetT, ClassT, ArgsT...>(LVREF | CONST);
}
template <typename RetT, class ClassT, typename... ArgsT> 
std::string Describe<RetT(ClassT::*)(ArgsT...) & noexcept>::describe() {
    return describeMemberPointer<RetT, ClassT, ArgsT...>(LVREF | NOEXCEPT);
}
template <typename RetT, class ClassT, typename... ArgsT> 
std::string Describe<RetT(ClassT::*)(ArgsT...) volatile &>::describe() {
    return describeMemberPointer<RetT, ClassT, ArgsT...>(LVREF | VOLATILE);
}
template <typename RetT, class ClassT, typename... ArgsT> 
std::string Describe<RetT(ClassT::*)(ArgsT...) volatile & noexcept>::describe() {
    return describeMemberPointer<RetT, ClassT, ArgsT...>(LVREF | VOLATILE | NOEXCEPT);
}
template <typename RetT, class ClassT, typename... ArgsT> 
std::string Describe<RetT(ClassT::*)(ArgsT...) const volatile &>::describe() {
    return describeMemberPointer<RetT, ClassT, ArgsT...>(LVREF | CONST | VOLATILE);
}
template <typename RetT, class ClassT, typename... ArgsT> 
std::string Describe<RetT(ClassT::*)(ArgsT...) const & noexcept>::describe() {
    return describeMemberPointer<RetT, ClassT, ArgsT...>(LVREF | CONST | NOEXCEPT);
}
template <typename RetT, class ClassT, typename... ArgsT> 
std::string Describe<RetT(ClassT::*)(ArgsT...) const volatile & noexcept>::describe() {
    return describeMemberPointer<RetT, ClassT, ArgsT...>(LVREF | CONST | VOLATILE | NOEXCEPT);
}
template <typename RetT, class ClassT, typename... ArgsT> 
std::string Describe<RetT(ClassT::*)(ArgsT...)&&>::describe() {
    return describeMemberPointer<RetT, ClassT, ArgsT...>(RVREF);
}
template <typename RetT, class ClassT, typename... ArgsT> 
std::string Describe<RetT(ClassT::*)(ArgsT...) const &&>::describe() {
    return describeMemberPointer<RetT, ClassT, ArgsT...>(RVREF | CONST);
}
template <typename RetT, class ClassT, typename... ArgsT> 
std::string Describe<RetT(ClassT::*)(ArgsT...) && noexcept>::describe() {
    return describeMemberPointer<RetT, ClassT, ArgsT...>(RVREF | NOEXCEPT);
}
template <typename RetT, class ClassT, typename... ArgsT> 
std::string Describe<RetT(ClassT::*)(ArgsT...) volatile &&>::describe() {
    return describeMemberPointer<RetT, ClassT, ArgsT...>(RVREF | VOLATILE);
}
template <typename RetT, class ClassT, typename... ArgsT> 
std::string Describe<RetT(ClassT::*)(ArgsT...) volatile && noexcept>::describe() {
    return describeMemberPointer<RetT, ClassT, ArgsT...>(RVREF | VOLATILE | NOEXCEPT);
}
template <typename RetT, class ClassT, typename... ArgsT> 
std::string Describe<RetT(ClassT::*)(ArgsT...) const volatile &&>::describe() {
    return describeMemberPointer<RetT, ClassT, ArgsT...>(RVREF | CONST | VOLATILE);
}
template <typename RetT, class ClassT, typename... ArgsT> 
std::string Describe<RetT(ClassT::*)(ArgsT...) const && noexcept>::describe() {
    return describeMemberPointer<RetT, ClassT, ArgsT...>(RVREF | CONST | NOEXCEPT);
}
template <typename RetT, class ClassT, typename... ArgsT> 
std::string Describe<RetT(ClassT::*)(ArgsT...) const volatile && noexcept>::describe() {
    return describeMemberPointer<RetT, ClassT, ArgsT...>(RVREF | CONST | VOLATILE | NOEXCEPT);
}

} // detail

///////////////////////////////////
// Main function
///////////////////////////////////
template <typename T>
std::string describe() {
    return detail::describe<T>();
}


///////////////////////////////////
// Sample code
///////////////////////////////////
#include <iostream>


struct X {
    using T = int *((*)[10]);
    T f(T, const unsigned long long * volatile * );
};

int main() {
    std::cout << describe<decltype(&X::f)>() << std::endl;
}

您可以使用模板。

template <typename T> const char* typeof(T&) { return "unknown"; }    // default
template<> const char* typeof(int&) { return "int"; }
template<> const char* typeof(float&) { return "float"; }

在上面的例子中,当类型不匹配时,它将打印“unknown”。

在c++ 11中,我们有decltype。在标准c++中,没有办法显示使用decltype声明的变量的确切类型。我们可以使用boost typeindex,即type_id_with_cvr (cvr代表const, volatile, reference)来打印如下所示的类型。

#include <iostream>
#include <boost/type_index.hpp>

using namespace std;
using boost::typeindex::type_id_with_cvr;

int main() {
  int i = 0;
  const int ci = 0;
  cout << "decltype(i) is " << type_id_with_cvr<decltype(i)>().pretty_name() << '\n';
  cout << "decltype((i)) is " << type_id_with_cvr<decltype((i))>().pretty_name() << '\n';
  cout << "decltype(ci) is " << type_id_with_cvr<decltype(ci)>().pretty_name() << '\n';
  cout << "decltype((ci)) is " << type_id_with_cvr<decltype((ci))>().pretty_name() << '\n';
  cout << "decltype(std::move(i)) is " << type_id_with_cvr<decltype(std::move(i))>().pretty_name() << '\n';
  cout << "decltype(std::static_cast<int&&>(i)) is " << type_id_with_cvr<decltype(static_cast<int&&>(i))>().pretty_name() << '\n';
  return 0;
}