使用 'auto' 类型推导 - 如何找出编译器推导的类型?
Using 'auto' type deduction - how to find out what type the compiler deduced?
如何找出编译器在使用 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)
typeid大部分时候可以用来获取变量的类型。它依赖于编译器,我看到它给出了奇怪的结果。 g++ 默认开启 RTTI,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> > >
我喜欢使用来自 Effective Modern C++ 的想法,它使用未实现的模板;输出的类型带有编译器错误:
template<typename T> struct TD;
现在对于自动变量 var
,在其定义后添加:
TD<decltype(var)> td;
并注意编译器的错误消息,它将包含 var
.
类型
作为旁注,要有效地打印出 nextTickTime
中的值,您应该显式转换为合适的 std::chrono::duration
and output the result of 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
这是一个 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> >
一个低技术含量的解决方案是将鼠标悬停在 nextTickTime
上,这在某些 GUI 中给出类型,否则在 cout
中的 nextTickTime
之后设置 .
和 select 一个看起来合理的值或函数。
一般来说,如果您知道您会使用auto
什么类型,如果您不知道它就不会用它。这有点违反直觉。
因此,如果您知道它是一个交互器,只需使用 auto 来减少咒语,如果结果是某种 未知 类型,您必须在使用 [=14 之前找出它是什么=].
This SO answer 提供了一个很好的函数来打印类型的名称(实际上是几个实现)。
此外,free, open-source, header-only library 提供了一种打印 和类型 的 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
如Daniel Jour所说,阅读错误信息:
... _Tp = std::chrono::time_point<
std::chrono::_V2::system_clock,
std::chrono::duration<
double, std::ratio<1l, 1000000000l> > > ...
不需要任何事先帮助器定义的低保真技巧是:
typename decltype(nextTickTime)::_
编译器会抱怨 _
不是任何类型 nextTickTime
的成员。
这里有一个强制编译错误的方法,显示tickTime
的类型:
struct {} baD = tickTime;
编译器推断的类型在错误信息中:
/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 --------------------------------------------------------------------------------------->
这是一个复杂的类型名称,但它在错误消息中。
@jonathan-oconnor points out that you can use the [[deprecated]]
在 C++14 中引入的属性以生成非常干净的解决方案:
template<typename T>
[[deprecated]] constexpr void printType(T const&) {}
不幸的是,MSVC 发出的诊断没有提到类型。 (example)
如何找出编译器在使用 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)
typeid大部分时候可以用来获取变量的类型。它依赖于编译器,我看到它给出了奇怪的结果。 g++ 默认开启 RTTI,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> > >
我喜欢使用来自 Effective Modern C++ 的想法,它使用未实现的模板;输出的类型带有编译器错误:
template<typename T> struct TD;
现在对于自动变量 var
,在其定义后添加:
TD<decltype(var)> td;
并注意编译器的错误消息,它将包含 var
.
作为旁注,要有效地打印出 nextTickTime
中的值,您应该显式转换为合适的 std::chrono::duration
and output the result of 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
这是一个 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> >
一个低技术含量的解决方案是将鼠标悬停在 nextTickTime
上,这在某些 GUI 中给出类型,否则在 cout
中的 nextTickTime
之后设置 .
和 select 一个看起来合理的值或函数。
一般来说,如果您知道您会使用auto
什么类型,如果您不知道它就不会用它。这有点违反直觉。
因此,如果您知道它是一个交互器,只需使用 auto 来减少咒语,如果结果是某种 未知 类型,您必须在使用 [=14 之前找出它是什么=].
This SO answer 提供了一个很好的函数来打印类型的名称(实际上是几个实现)。
此外,free, open-source, header-only library 提供了一种打印 和类型 的 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
如Daniel Jour所说,阅读错误信息:
... _Tp = std::chrono::time_point<
std::chrono::_V2::system_clock,
std::chrono::duration<
double, std::ratio<1l, 1000000000l> > > ...
不需要任何事先帮助器定义的低保真技巧是:
typename decltype(nextTickTime)::_
编译器会抱怨 _
不是任何类型 nextTickTime
的成员。
这里有一个强制编译错误的方法,显示tickTime
的类型:
struct {} baD = tickTime;
编译器推断的类型在错误信息中:
/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 --------------------------------------------------------------------------------------->
这是一个复杂的类型名称,但它在错误消息中。
@jonathan-oconnor points out that you can use the [[deprecated]]
在 C++14 中引入的属性以生成非常干净的解决方案:
template<typename T>
[[deprecated]] constexpr void printType(T const&) {}
不幸的是,MSVC 发出的诊断没有提到类型。 (example)