Reputation: 15003
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
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
Reputation: 66230
It seems to me that you're asking two different and independent questions.
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>> );
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
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