pic11
pic11

Reputation: 15003

Print deduced template arguments at compile time

How to print automatically deduced template arguments at compile time?

std::pair x(1, 2.0);

In the above example the type of x is std::pair<int, double>. Is there a way to print the deduced type of x at compile time, e.g. as std::pair<int, double> or in some other readable form?

Edit. I am using a library (DPC++) that relies on C++ 17 automatic template argument deduction. Sometimes it is difficult to guess how template argument were deduces.

Upvotes: 0

Views: 482

Answers (3)

voodooattack
voodooattack

Reputation: 1176

The quickest and simplest method I've found so far to print the deduced type of anything at compile-time is to divide it by nullptr:

#include <tuple>

int main() {
    auto a = std::make_tuple(0, 10ul, +[](int&&) -> int { return 42; });
    a / nullptr;
}

GCC's output looks like this:

 In function 'int main()':
5:7: error: no match for 'operator/' (operand types are 'std::tuple<int, long unsigned int, int (*)(int&&)>' and 'std::nullptr_t')

Upvotes: 0

max66
max66

Reputation: 66230

It seems to me that you're asking two different and independent questions.

  1. given an object obtained from CTAD, how obtain the deduced exact type of the object.

For this question the answer is simple: it's a work for decltype(), that permit something as

std::pair x{1, 2.0};

decltype(x) y{2, 3.0};  // y is std::pair<int, double>

static_assert( std::is_same_v<decltype(x), std::pair<int, double>> );
static_assert( std::is_same_v<decltype(y), std::pair<int, double>> );
  1. how print, in a human readable form, the type of an object?

C++ make available an operator, typeid(), that return an object of a class, std::type_info, with, among other things, a name() method that return a C-style string description of the type.

So you can write

std::pair x{1, 2.0};

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

Unfortunately the description string is implementation specific and, for non trivial types, not really descriptive for a human being.

For example, from that code, I obtain

St4pairIidE

from g++ and

NSt3__14pairIidEE

from clang++.

Obviously, if you're interested in the template parameter deduced for the std::pair, you can deduce the single types (int and double) and print them.

For example, you can write a function as follows

template <typename T1, typename T2>
void print_pair_types (std::pair<T1, T2> const &)
 {
   std::cout << "First pair type: " << typeid(T1).name() << std::endl;
   std::cout << "Second pair type: " << typeid(T2).name() << std::endl;
 }

and call it with x

std::pair x{1, 2.0};

print_pair_types(x);

From both g++ and clang++ I obtain

First pair type: i
Second pair type: d

Upvotes: 1

Ayjay
Ayjay

Reputation: 3433

Here's one (admittedly roundabout and verbose) approach:

#include <utility>

template <class T>
struct type_reader {
    type_reader() {
        int x{0};
        if (x = 1) {} // trigger deliberate warning
    }
};

int main() {
    std::pair x(1, 2.0);
    type_reader<decltype(x)> t;
}

Depending on your compiler and settings, you can get a warning like

<source>:7:19: warning: using the result of an assignment as a condition without parentheses [-Wparentheses]
        if (x = 1) {} // trigger deliberate warning
<source>:13:34: note: in instantiation of member function 'type_reader<std::pair<int, double>>::type_reader' requested here
    type_reader<decltype(x)> t;

and you can see the type std::pair<int, double>> in that mess if you squint.

Upvotes: 1

Related Questions