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