microseconds c++ c++11 auto chrono

c++ - microseconds - Uso de la deducción de tipo ''automático'': ¿cómo averiguar qué tipo dedujo el compilador?



usleep c++ linux (10)

Aquí hay una forma de forzar un error de compilación, que muestra el tipo de tickTime :

struct {} baD = tickTime;

¿Cómo puedo averiguar qué tipo dedujo el compilador al usar la palabra clave auto ?

Ejemplo 1: más simple

auto tickTime = 0.001;

¿Se dedujo esto como un float o un double?

Ejemplo 2: Más complejo (y mi dolor de cabeza actual):

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

¿Qué tipo es nextTickTime ?

El problema que tengo es cuando intento enviar nextTickTime a std::cout . Obtuve el siguiente 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)


Aquí hay una versión typeid que usa boost::core::demangle para obtener el nombre del tipo en tiempo de ejecución.

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

Lo que imprime esto en mi sistema:

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


Como dijo Daniel Jour , lea el mensaje de error:

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


Como nota al margen, para imprimir eficazmente el valor en nextTickTime , debe convertir explícitamente a un std::chrono::duration nextTickTime adecuado y generar el resultado de 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


El tipo deducido por el compilador está en el mensaje de error:

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

Es un nombre de tipo complicado pero está allí en el mensaje de error.


Me gusta usar la idea de Effective Modern C ++ que usa una plantilla no implementada; el tipo se muestra con un error de compilación:

template<typename T> struct TD;

Ahora para la variable automática var , después de su definición agregue:

TD<decltype(var)> td;

Y mire el mensaje de error para su compilador, contendrá el tipo de var .


Un truco de baja fidelidad que no requiere ninguna definición de ayuda previa es:

typename decltype(nextTickTime)::_

El compilador se quejará de que _ no es miembro del tipo que sea nextTickTime .


Una solución de baja tecnología es pasar el mouse sobre nextTickTime que, en algunas GUI, le da al tipo set a . después de nextTickTime en cout y seleccione un valor o función de aspecto razonable.

En general, si sabe de qué tipo obtiene, use auto si no lo sabe , no lo use. Lo cual es un poco contrario a la intuición.

Entonces, si sabe que es un interador, simplemente use auto para reducir los encantamientos, si el resultado es de algún tipo desconocido , debe averiguar qué es antes de usar auto .

Ver también Herb, Andrei y Scott discutiendo auto


typeid se puede usar para obtener el tipo de variable la mayor parte del tiempo. Depende del compilador y lo he visto dar resultados extraños. g ++ tiene RTTI activado por defecto, no estoy seguro en el lado de 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> > >


Esta respuesta SO ofrece una buena función para imprimir el nombre de un tipo (en realidad, un par de implementaciones).

Además, esta biblioteca gratuita, de código abierto y solo encabezado ofrece una buena manera de imprimir el valor y el tipo de chrono::duration s.

Poniendo estas dos utilidades juntas:

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

Esta salida para mí:

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