Comment savoir quel type le compilateur a déduit lors de l'utilisation du mot clé auto
?
Exemple 1: plus simple
auto tickTime = 0.001;
Cela a-t-il été déduit comme float
ou double?
Exemple 2: Plus complexe (et mon mal de tête actuel):
typedef std::ratio<1, 1> sec;
std::chrono::duration<double, sec > timePerTick2{0.001};
auto nextTickTime = std::chrono::high_resolution_clock::now() + timePerTick2;
De quel type est nextTickTime
?
Le problème que je rencontre est lorsque j'essaie d'envoyer nextTickTime
à std::cout
. J'obtiens l'erreur suivante:
./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)
J'aime utiliser l'idée de Effective Modern C++ qui utilise un modèle non implémenté; le type est sorti avec une erreur de compilation:
template<typename T> struct TD;
Maintenant, pour la variable automatique var
, après sa définition, ajoutez:
TD<decltype(var)> td;
Et regardez le message d'erreur de votre compilateur, il contiendra le type de var
.
Une astuce lo-fi qui ne nécessite aucune définition d'aide préalable est:
typename decltype(nextTickTime)::_
Le compilateur se plaindra que _
n'est pas membre de quelque type que ce soit nextTickTime
.
Voici une version typeid
qui utilise boost::core::demangle
pour obtenir le nom du type lors de l'exécution.
#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;
}
Qui imprime cela sur mon système:
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> >
typeid peut être utilisé pour obtenir le type de variable la plupart du temps. Il dépend du compilateur et je l'ai vu donner des résultats étranges. g ++ a RTTI activé par défaut, pas sûr du côté 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> > >
Comme Daniel Jour l'a dit, lisez le message d'erreur:
... _Tp = std::chrono::time_point<
std::chrono::_V2::system_clock,
std::chrono::duration<
double, std::ratio<1l, 1000000000l> > > ...
Le type déduit par le compilateur se trouve dans le message d'erreur:
/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 --------------------------------------------------------------------------------------->
C'est un nom de type compliqué mais il est là dans le message d'erreur.
This SO answer donne une fonction Nice pour imprimer le nom d'un type (en fait quelques implémentations).
De plus, cette bibliothèque libre, open-source et en-tête uniquement donne un bon moyen d'imprimer la valeur et le type de chrono::duration
s.
Associer ces deux utilitaires:
#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';
}
Cette sortie pour moi:
std::__1::chrono::time_point<std::__1::chrono::steady_clock, std::__1::chrono::duration<double, std::__1::ratio<1, 1000000000> > >
4.8530542088e+14ns
Une solution low-tech passe la souris sur nextTickTime
qui dans certaines interfaces graphiques donne au type else set un .
après nextTickTime
dans le cout
et sélectionnez une valeur ou une fonction d'aspect raisonnable.
En général, si vous savez quel type vous obtenez utilisez auto
si vous ne sais pas il ne l'utilise pas. Ce qui est un peu contre-intuitif.
Donc, si vous savez que c'est un interateur, utilisez simplement auto pour réduire les incantations, si le résultat est un type inconnu , vous devez savoir ce que c'est avant d'utiliser auto
.
Voir aussi Herb, Andrei et Scott discutant de auto
Voici un moyen de forcer une erreur de compilation, qui montre le type de tickTime
:
struct {} baD = tickTime;
En guise de remarque, pour imprimer efficacement la valeur dans nextTickTime
, vous devez explicitement convertir en une valeur appropriée std::chrono::duration
et afficher le résultat 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