使用'auto'类型推导 - 如何找出编译器推导出的类型?

时间:2016-08-08 02:39:06

标签: c++ c++11 auto chrono

如何找出编译器在使用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)

11 个答案:

答案 0 :(得分:100)

我喜欢使用来自 Effective Modern C ++ 的想法,它使用未实现的模板;输出类型时出现编译错误:

window.alert(localStorage.getItem('checkFired'));

现在对于自动变量 template<typename T> struct TD; ,在其定义之后添加:

var

并查看编译器的错误消息,它将包含 TD<decltype(var)> td; 的类型。

答案 1 :(得分:26)

不需要任何先前助手定义的低保真技巧是:

typename decltype(nextTickTime)::_

编译器会抱怨_不是nextTickTime类型的成员。

答案 2 :(得分:8)

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

答案 3 :(得分:5)

typeid可用于在大多数时间获取变量的类型。它依赖于编译器,我看到它给出了奇怪的结果。 g ++默认启用RTTI,在Windows端不确定。

.cke_toolbox

答案 4 :(得分:3)

Daniel Jour所述,请阅读错误消息:

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

答案 5 :(得分:2)

低技术解决方案是将鼠标悬停在nextTickTime上,在某些GUI中,.nextTickTime之后的其他类型设置为cout并选择合理的外观价值或功能。

一般情况下,如果您知道您使用auto的类型,如果不知道则不使用它。这有点反直觉。

因此,如果你知道它的一个交互者只是使用auto来减少咒语,如果结果是一些未知类型,你必须在使用auto之前找出它是什么。

另见Herb, Andrei and Scott discussing auto

答案 6 :(得分:2)

This SO answer提供了一个很好的函数来打印出一个类型的名称(实际上是几个实现)。

此外,此free, open-source, header-only library提供了一种打印出{em>并输入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

答案 7 :(得分:2)

编译器推导出的类型在错误消息中:

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

这是一个复杂的类型名称,但它出现在错误消息中。

答案 8 :(得分:1)

作为旁注,要有效打印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

答案 9 :(得分:1)

这是一种强制编译错误的方法,它显示tickTime的类型:

struct {} baD = tickTime;

答案 10 :(得分:0)

@jonathan-oconnor points out 您可以使用 C++14 中引入的 [[deprecated]] 属性来生成一个非常干净的解决方案:

template<typename T>
[[deprecated]] constexpr void printType(T const&) {}

不幸的是,MSVC 发出的诊断并没有提到类型。 (example)