C++17 std::in_place_type, std::in_place_index_t, std::in_place_type_t 这些的用法
2017-10-01 18:07
561 查看
C++17标准提供了三个新东西,
std::optional,
std::variant,
std::any
概念和使用方法都挺简单的。
可以参考cppreference等各大网页。
但是如果点开看的话,会发现有几个构造函数有点奇怪,用到了
std::in_place,
std::in_place_type,
std::in_place_index,
std::in_place_t,
std::in_place_type_t,
std::in_place_index_t
这些奇怪的东西。
其实都挺简单的,但是还是有一点小的需要注意的地方,我第一次就有点懵,折腾了半天,现在发出来一个是帮助自
己记忆,一个是免得别人再耽误时间了。
如果需要看示例代码,可以看最下面我附上的知乎链接。(其实没必要看,挺简单的)
看cppreference解释,这些是用来强调原位构造的tag,消除歧义。
乍一看其实还是有点懵,
举例来说
std::variant的构造函数,见http://en.cppreference.com/w/cpp/utility/variant
第五个
意思是以T类型的初始值来初始化variant,这个值是什么呢?
用args来构建出来的T,就是这个初始值。
第七个
意思是以variant的模板参数第I个的类型来初始化variant,值是args构建出来的T
这里看英文写的其实有点含糊。。可能不是英语母语的原因吧。。刚开始有点搞不清,到底是以args来构建T,还是以
args的各个值来构造variant的各种类型的值。
后来拿代码试了试,确认的确是用args来构造T。
想想也对,variant是当作类型安全的union用的,怎么可能一下初始化所有类型的值。
注意第六个和第八个
同时用到了std::initializer_list和...Args,乍看上去也挺懵的。都用了initializer_list了,干嘛还加个参数包?
随便用一个不就行了?
其实这里是我自己犯迷糊了,initializer_list是同类型的一串值,和参数包还有
以大括号初始化的时候传进去一堆类型
不同的值,那个不一样。尽管长得挺像的,但是不是一个概念。
initializer_list完全可以和别的参数一起用,来构造一个东西。
举例来说std::vector有一个构造函数可以接受initializer_list和allocator
见vector的第八个构造函数
http://en.cppreference.com/w/cpp/container/vector/vector
至于为什么initializer_list不能被包含在参数包里,要单独列出来,可以去查,我也记得不太清楚。好象是模板参数推
导歧义的原因?
其他的我就不详细说了,理解了一个以后,别的都挺直白的。
比如说std::in_place,用来明确要求使用某个std::optional的构造函数等
还有一点要注意的是
std::in_place_type_t是一个模板类(template
class,是一个特殊的class)
std::in_place_type是一个模板变量(template
variable,是一个特殊的variable)
变量模板是C++17的新特性,可以自己去查。
注意到
std::in_place_type的定义
是inline constexpr的,所以尽量使用std::in_place这种模板变量,应该会比构造一个std::in_place_type_t的实例要更
效率一点,不过也不能确定,tag只是一个空类,说不定构造就被优化了呢?(inline
variable也是C++17的新东西,
可以见我另一篇博客http://blog.csdn.net/zhangfengz1995/article/details/78143360)
相关的网页
我在知乎的自问自答
https://www.zhihu.com/question/66032208
还有stackoverflow的自问自答。。。
https://stackoverflow.com/questions/46508850/why-is-there-a-constructor-accepting-both-initializer-list-and-a-parameter-pack
。。看来这个问题是有点奇葩,有点像脑筋急转弯,我一描述大家一听都有道理,结果其实我们都被唬到了。。最后
仔细想想原来就这么简单。
std::optional,
std::variant,
std::any
概念和使用方法都挺简单的。
可以参考cppreference等各大网页。
但是如果点开看的话,会发现有几个构造函数有点奇怪,用到了
std::in_place,
std::in_place_type,
std::in_place_index,
std::in_place_t,
std::in_place_type_t,
std::in_place_index_t
这些奇怪的东西。
其实都挺简单的,但是还是有一点小的需要注意的地方,我第一次就有点懵,折腾了半天,现在发出来一个是帮助自
己记忆,一个是免得别人再耽误时间了。
如果需要看示例代码,可以看最下面我附上的知乎链接。(其实没必要看,挺简单的)
看cppreference解释,这些是用来强调原位构造的tag,消除歧义。
乍一看其实还是有点懵,
举例来说
std::variant的构造函数,见http://en.cppreference.com/w/cpp/utility/variant
第五个
template<class T, class... Args > constexpr explicit variant(std::in_place_type_t<T>,Args&&... args);
意思是以T类型的初始值来初始化variant,这个值是什么呢?
用args来构建出来的T,就是这个初始值。
第七个
template<std::size_tI, class... Args > constexpr explicit variant(std::in_place_index_t<I>,Args&&... args);
意思是以variant的模板参数第I个的类型来初始化variant,值是args构建出来的T
这里看英文写的其实有点含糊。。可能不是英语母语的原因吧。。刚开始有点搞不清,到底是以args来构建T,还是以
args的各个值来构造variant的各种类型的值。
后来拿代码试了试,确认的确是用args来构造T。
想想也对,variant是当作类型安全的union用的,怎么可能一下初始化所有类型的值。
注意第六个和第八个
template<class T, class U, class... Args > constexpr explicit variant(std::in_place_type_t<T>, std::initializer_list<U>il, Args&&... args);
template<std::size_tI, class U, class... Args > constexprexplicit variant(std::in_place_index_t<I>, std::initializer_list<U>il, Args&&... args);
同时用到了std::initializer_list和...Args,乍看上去也挺懵的。都用了initializer_list了,干嘛还加个参数包?
随便用一个不就行了?
其实这里是我自己犯迷糊了,initializer_list是同类型的一串值,和参数包还有
以大括号初始化的时候传进去一堆类型
不同的值,那个不一样。尽管长得挺像的,但是不是一个概念。
initializer_list完全可以和别的参数一起用,来构造一个东西。
举例来说std::vector有一个构造函数可以接受initializer_list和allocator
见vector的第八个构造函数
http://en.cppreference.com/w/cpp/container/vector/vector
至于为什么initializer_list不能被包含在参数包里,要单独列出来,可以去查,我也记得不太清楚。好象是模板参数推
导歧义的原因?
其他的我就不详细说了,理解了一个以后,别的都挺直白的。
比如说std::in_place,用来明确要求使用某个std::optional的构造函数等
还有一点要注意的是
std::in_place_type_t是一个模板类(template
class,是一个特殊的class)
std::in_place_type是一个模板变量(template
variable,是一个特殊的variable)
变量模板是C++17的新特性,可以自己去查。
注意到
std::in_place_type的定义
template <class T> struct in_place_type_t { explicit in_place_type_t() = default; }; template <class T> inline constexpr std::in_place_type_t<T> in_place_type{};
是inline constexpr的,所以尽量使用std::in_place这种模板变量,应该会比构造一个std::in_place_type_t的实例要更
效率一点,不过也不能确定,tag只是一个空类,说不定构造就被优化了呢?(inline
variable也是C++17的新东西,
可以见我另一篇博客http://blog.csdn.net/zhangfengz1995/article/details/78143360)
相关的网页
我在知乎的自问自答
https://www.zhihu.com/question/66032208
还有stackoverflow的自问自答。。。
https://stackoverflow.com/questions/46508850/why-is-there-a-constructor-accepting-both-initializer-list-and-a-parameter-pack
。。看来这个问题是有点奇葩,有点像脑筋急转弯,我一描述大家一听都有道理,结果其实我们都被唬到了。。最后
仔细想想原来就这么简单。
相关文章推荐
- C++ std::string --- 你可能不知道的一些用法
- C++ 使用oci访问数据库出现“Column: 2<DOUBLE>, datatype in operator <</>>: CHAR”
- C++ std::string --- 你可能不知道的一些用法
- C++ using namespace std 用法深入解析
- gcc 4.3.2 编译时 发生 error: redeclaration of C++ built-in type 'bool' 错误
- c++ std vector用法介绍
- 雇佣问题原址排列给定数组(randomize In Place)-c++代码实现及运行实例结果
- 4 type cast operators in C++
- Advanced Run Time Type Identification in C++ Part II(Property Library An Implementation of RTTI in C++)
- QtCreator编译报错 redeclaration of C++ built-in type 'wchar_t'
- C++学习【原创】归并排序(inplace_merge函数的应用)
- How to use libcurl in C++ with std::string
- Effective C++ Item 17 Store newed objects in smart pointer in standalone statements
- Question 17: Which of the following identify const-correctness failures in the C++ program below?
- 4 type cast operators in C++
- How to convert std::string to LPCWSTR in C++ (Unicode)
- C++ std_pair用法
- Question 35: Protected, or private, inheritance, as opposed to public inheritance, models which type of relationship in C++?
- c++中关于智能指针std::tr1::shared_ptr的用法
- C++ std::vector : 用法与技巧