web-dev-qa-db-fra.com

Utiliser la déduction de type «automatique» - comment savoir quel type le compilateur a déduit?

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)
69
kmiklas

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.

101
marcinj

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.

26
John McFarlane

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

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> > >
5
Matthew Fisher

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> > > ...
3
Jacob Krall

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.

2
R Sahu

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::durations.

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
2
Howard Hinnant

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

2
Surt

Voici un moyen de forcer une erreur de compilation, qui montre le type de tickTime:

struct {} baD = tickTime;
1
pts

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