Использование вывода типа "auto" - как узнать, какой тип вывел компилятор?

Как я могу узнать, какой тип вывел компилятор при использовании ключевого слова auto?

Пример 1: Упрощенный

auto tickTime = 0.001;

Было ли это выведено как float или double?

Пример 2: Более сложная (и моя нынешняя головная боль):

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

Какой тип nextTickTime?

Проблема, с которой я столкнулась, - это когда я пытаюсь отправить nextTickTime на std::cout. Я получаю следующую ошибку:

./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)

Ответ 1

Мне нравится использовать идею из Effective Modern С++, которая использует не реализованный шаблон; тип выводится с ошибкой компилятора:

 template<typename T> struct TD;

Теперь для автоматической переменной var после ее определения добавьте:

 TD<decltype(var)> td;

И посмотрите сообщение об ошибке для своего компилятора, он будет содержать тип var.

Ответ 2

Lo-fi трюк, который не требует каких-либо предварительных описаний помощника:

typename decltype(nextTickTime)::_

Компилятор будет жаловаться, что _ не является членом любого типа nextTickTime.

Ответ 3

Здесь a typeid версия, которая использует boost::core::demangle для получения имени типа во время выполнения.

#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;
}

Что печатает это в моей системе:

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> >

Ответ 4

typeid может использоваться для получения типа переменной большую часть времени. Это зависит от компилятора, и я видел, что он дает странные результаты. g++ имеет RTTI по ​​умолчанию, не уверен на стороне Windows.

#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> > >

Ответ 5

Как Даниэль Джур сказал, прочитайте сообщение об ошибке:

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

Ответ 6

Низкотехнологичное решение наводит указатель мыши на nextTickTime, который в некоторых графических интерфейсах предоставляет тип else, а затем . после nextTickTime в cout и выберите разумное значение или функцию.

В общем, если вы знаете, какой тип вы используете auto, если вы не знаете, что он его не использует. Что немного интуитивно понятно.

Итак, если вы знаете, что его интернатор просто использует auto для уменьшения заклинаний, если в результате есть какой-то тип неизвестный, вам нужно выяснить, что это такое, прежде чем использовать auto.

См. также Трава, Андрей и Скотт обсуждают auto

Ответ 7

Этот ответ SO дает приятную функцию для печати имени типа (фактически, нескольких реализаций).

Кроме того, свободная библиотека с открытым исходным кодом, только для заголовков дает хороший способ распечатать значение и тип chrono::duration с.

Объединение этих двух утилит:

#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';
}

Этот вывод для меня:

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

Ответ 8

Тип, выводимый компилятором, находится в сообщении об ошибке:

/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 --------------------------------------------------------------------------------------->

Это сложное имя типа, но оно есть в сообщении об ошибке.

Ответ 9

В качестве примечания, чтобы эффективно распечатать значение в nextTickTime, вы должны явно преобразовать в подходящий std::chrono::duration и вывести результат 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

Ответ 10

Вот способ принудительной компиляции, который показывает тип tickTime:

struct {} baD = tickTime;