1

I have some nested typedefs which I am trying to debug. The first I want to do is to print them out so I can see how they are instantiated.

E.g.

 using tt = std::conditional<conditionForType1, type_1, type_2>;

where type_1 and type_2 are two other evaluated aliases. How can I print the content of tt, type_1, and type_2

ATK
  • 1,296
  • 10
  • 26
  • 1
    If you want to print the type at run-time, I'd start with [typeid](https://en.cppreference.com/w/cpp/language/typeid) – SergeyA Jun 07 '21 at 19:19

3 Answers3

3

A quick and dirty way:

template <typename T>
void print_type()
{
    #ifndef _MSC_VER
    std::cout << __PRETTY_FUNCTION__ << '\n';
    #else
    std::cout << __FUNCSIG__ << '\n';
    #endif
}

What exactly is printed depends on the compiler. For print_type<int>();, my Clang prints void print_type() [T = int].

See this thread for removing anything other than the type name from such strings.

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
  • What does it print if you pass `print_type()`? – jxh Jun 07 '21 at 19:59
  • @jxh On my Clang it prints `void print_type() [T = std::conditional]` (given `constexpr bool conditionForType1 = true;`). – HolyBlackCat Jun 07 '21 at 20:03
  • Works with GCC too. Now, I'm curious what MSVC would print. – jxh Jun 07 '21 at 20:05
  • @jxh `void __cdecl print_type>(void)` I know you're expecting one of them to print `tt`, but nope. If it worked like this, it could have some use for stateful metaprogramming... – HolyBlackCat Jun 07 '21 at 20:10
  • The reason I half thought it would is because I originally tested `void print_type(tt){ ... }` and that is what it print. – jxh Jun 07 '21 at 20:27
1

I use the compiler to handle this for me. By declaring a class template like

template <typename T>
struct type;

and not defining it, you can use it in code like

int main()
{
    struct foo {};
    struct bar {};
    
    foo f;
    
    type<int>{};
    type<decltype(f)>{};
    type<bar>{};
}

Which will give you a compiler error like

main.cpp: In function 'int main()':
main.cpp:25:15: error: invalid use of incomplete type 'struct type<int>'
   25 |     type<int>{};
      |               ^
main.cpp:14:8: note: declaration of 'struct type<int>'
   14 | struct type;
      |        ^~~~
main.cpp:26:23: error: invalid use of incomplete type 'struct type<main()::foo>'
   26 |     type<decltype(f)>{};
      |                       ^
main.cpp:14:8: note: declaration of 'struct type<main()::foo>'
   14 | struct type;
      |        ^~~~
main.cpp:27:15: error: invalid use of incomplete type 'struct type<main()::bar>'
   27 |     type<bar>{};
      |               ^
main.cpp:14:8: note: declaration of 'struct type<main()::bar>'
   14 | struct type;
      |        ^~~~

And it gives you the type used in the template parameter as a convenient error message.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
0

The typeid operator returns an object of type type_info, which has a name() method. You can use this to get a string representation of the type.

std::cout << typeid(tt).name() << '\n';

If you use , there is an API you can call to demangle the name into something more human readable. On my system, the program:

using tt = std::conditional<true, int, double>;

int main () {
    int status;
    auto &&ti = typeid(tt);
    char *pretty = abi::__cxa_demangle(ti.name(), 0, 0, &status);
    std::cout << ti.name() << '\n';
    std::cout << pretty << '\n';
    free(pretty);
}

Produces the output:

St11conditionalILb1EidE
std::conditional<true, int, double>

Try it online!

jxh
  • 69,070
  • 8
  • 110
  • 193