Using 'auto' type deduction - how to find out what type the compiler deduced?

How can I find out what type the compiler deduced when using the auto keyword?

Example 1: Simpler

auto tickTime = 0.001;

Was this deduced as a float or a double?

Example 2: More complex (and my present headache):

typedef std::ratio<1, 1> sec;
std::chrono::duration<double, sec > timePerTick2{0.001};
auto nextTickTime = std::chrono::high_resolution_clock::now() + timePerTick2;

What type is nextTickTime?

The problem I'm having is when I try to send nextTickTime to std::cout. I get the following error:

./main.cpp: In function ‘int main(int, char**)’:
./main.cpp:143:16: error: cannot bind ‘std::basic_ostream<char>’ lvalue to ‘std::basic_ostream<char>&&’
std::cout << std::setprecision(12) << nextTickTime << std::endl; // time in seconds
^
In file included from /usr/include/c++/4.8.2/iostream:39:0,
from ./main.cpp:10:
/usr/include/c++/4.8.2/ostream:602:5: error:   initializing argument 1 of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<double, std::ratio<1l, 1000000000l> > >]’
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
13473 次浏览

typeid can be used to get the type of variable most of the time. It is compiler dependent and I've seen it give strange results. g++ has RTTI on by default, not sure on the Windows side.

#include <iostream>
#include <typeinfo>
#include <stdint.h>
#include <chrono>
#include <ctime>


typedef std::ratio<1, 1> sec;
int main()
{
auto tickTime = .001;
std::chrono::duration<double, sec > timePerTick2{0.001};
auto nextTickTime = std::chrono::high_resolution_clock::now() + timePerTick2;
std::cout << typeid(tickTime).name() << std::endl;
std::cout << typeid(nextTickTime).name() << std::endl;


return 0;
}


./a.out | c++filt


double
std::__1::chrono::time_point<std::__1::chrono::steady_clock, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > >

I like to use idea from Effective Modern C++ which uses non-implemented template; the type is output with compiler error:

 template<typename T> struct TD;

Now for auto variable var, after its definition add:

 TD<decltype(var)> td;

And watch error message for your compiler, it will contain type of var.

As a side note, to effectively print out the value in nextTickTime you should explicitly convert to a suitable std::chrono::duration and output the result of duration::count.

using std::chrono::duration_cast;
using std::chrono::seconds;


auto baseTime = ...;
std::cout << std::setprecision(12) << duration_cast<seconds>(nextTickTime - baseTime).count()
<< std::endl; // time in seconds

Here's a typeid version that uses boost::core::demangle to get the type name at runtime.

#include <string>
#include <iostream>
#include <typeinfo>
#include <vector>
using namespace std::literals;


#include <boost/core/demangle.hpp>


template<typename T>
std::string type_str(){ return boost::core::demangle(typeid(T).name()); }


auto main() -> int{
auto make_vector = [](auto head, auto ... tail) -> std::vector<decltype(head)>{
return {head, tail...};
};


auto i = 1;
auto f = 1.f;
auto d = 1.0;
auto s = "1.0"s;
auto v = make_vector(1, 2, 3, 4, 5);


std::cout
<< "typeof(i) = " << type_str<decltype(i)>() << '\n'
<< "typeof(f) = " << type_str<decltype(f)>() << '\n'
<< "typeof(d) = " << type_str<decltype(d)>() << '\n'
<< "typeof(s) = " << type_str<decltype(s)>() << '\n'
<< "typeof(v) = " << type_str<decltype(v)>() << '\n'
<< std::endl;
}

Which prints this on my system:

typeof(i) = int
typeof(f) = float
typeof(d) = double
typeof(s) = std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >
typeof(v) = std::vector<int, std::allocator<int> >

A low tech solution is hover the mouse over nextTickTime which in some GUIs gives the type else set a . after nextTickTime in the cout and select a reasonable looking value or function.

In general if You know what type You get use auto if you don't know it don't use it. Which is a bit counter intuitive.

So if you know its a interator just use auto to reduce the incantations, if the result is some unknown type you have to find out what it is before using auto.

See also Herb, Andrei and Scott discussing auto

This SO answer gives a nice function for printing out the name of a type (actually a couple of implementations).

Additionally this free, open-source, header-only library gives a nice way to print out the value and type of chrono::durations.

Putting these two utilities together:

#include "chrono_io.h"
#include "type_name.h"
#include <iomanip>
#include <iostream>


int
main()
{
using namespace date;
typedef std::ratio<1, 1> sec;
std::chrono::duration<double, sec > timePerTick2{0.001};
auto nextTickTime = std::chrono::high_resolution_clock::now() + timePerTick2;
std::cout << type_name<decltype(nextTickTime)>() << '\n';
std::cout << std::setprecision(12) << nextTickTime.time_since_epoch() << '\n';
}

This output for me:

std::__1::chrono::time_point<std::__1::chrono::steady_clock, std::__1::chrono::duration<double, std::__1::ratio<1, 1000000000> > >
4.8530542088e+14ns

As Daniel Jour said, read the error message:

... _Tp = std::chrono::time_point<
std::chrono::_V2::system_clock,
std::chrono::duration<
double, std::ratio<1l, 1000000000l> > > ...

A lo-fi trick that doesn't require any prior helper definitions is:

typename decltype(nextTickTime)::_

The compiler will complain that _ isn't a member of whatever type nextTickTime is.

Here is a way to force a compile error, which shows the type of tickTime:

struct {} baD = tickTime;

The type deduced by the compiler is in the error message:

/usr/include/c++/4.8.2/ostream:602:5: error:   initializing argument 1 of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>;
_Tp = std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<double, std::ratio<1l, 1000000000l> > >]’
^^   <-------- the long type name --------------------------------------------------------------------------------------->

It's a complicated type name but it is there in the error message.

@jonathan-oconnor points out that you can use the [[deprecated]] attribute introduced in C++14 to produce a very clean solution:

template<typename T>
[[deprecated]] constexpr void printType(T const&) {}

Unfortunately though, the diagnostic emitted by MSVC doesn't mention the type. (example)