为什么在 GCC 中 std::set 推导失败?
Why does deduction fail for std::set in GCC?
我有一个 std::set
允许从迭代器范围中扣除。
#include <iostream>
#include <set>
int main()
{
std::set s1 = {1,2,3,4};
std::set s2(s1.begin(), s1.end());
}
GCC 中的上述程序 failed to compile。
这里std::set
为什么推演失败?
只需使用当前的 GCC 版本(此时为 8.0.0)即可构建。 std::set
的模板推导指南似乎并未在较旧的 GCC 版本的标准库中实现。
std::set
的迭代器构造函数的演绎指南最近才添加到 gcc HEAD 中。
根据 gcc-mirror/gcc
在 GitHub 的说法,std::set
的迭代器构造函数的推导指南是 added and merged to libstdc++-v3 less than two weeks ago、
(Extract from diff for libstdc++-v3/include/bits/stl_set.h
)
+#if __cpp_deduction_guides >= 201606
+
+ template<typename _InputIterator,
+ typename _Compare =
+ less<typename iterator_traits<_InputIterator>::value_type>,
+ typename _Allocator =
+ allocator<typename iterator_traits<_InputIterator>::value_type>,
+ typename = _RequireInputIter<_InputIterator>,
+ typename = _RequireAllocator<_Allocator>>
+ set(_InputIterator, _InputIterator,
+ _Compare = _Compare(), _Allocator = _Allocator())
+ -> set<typename iterator_traits<_InputIterator>::value_type,
+ _Compare, _Allocator>;
+
+ template<typename _Key, typename _Compare = less<_Key>,
+ typename _Allocator = allocator<_Key>,
+ typename = _RequireAllocator<_Allocator>>
+ set(initializer_list<_Key>,
+ _Compare = _Compare(), _Allocator = _Allocator())
+ -> set<_Key, _Compare, _Allocator>;
+
+ template<typename _InputIterator, typename _Allocator,
+ typename = _RequireInputIter<_InputIterator>,
+ typename = _RequireAllocator<_Allocator>>
+ set(_InputIterator, _InputIterator, _Allocator)
+ -> set<typename iterator_traits<_InputIterator>::value_type,
+ less<typename iterator_traits<_InputIterator>::value_type>,
+ _Allocator>;
+
+ template<typename _Key, typename _Allocator,
+ typename = _RequireAllocator<_Allocator>>
+ set(initializer_list<_Key>, _Allocator)
+ -> set<_Key, less<_Key>, _Allocator>;
+
+#endif
这很自然地解释了为什么模板参数推导对于早期版本的 gcc 的迭代器构造函数的模板化 set
失败,例如7.2.0。如果使用当前的 gcc trunk (gcc HEAD 8.0.0 20171103 (experimental)) the deduction guides above are available,并且迭代器构造函数的模板参数推导也成功。
至于为什么模板参数推导在 gcc 7.2.0 中已经成功用于 std::initializer_list
构造函数(没有推导指南;指南也在上面的提交中添加),正如在 @JohnZwinck deleted answer,这些构造函数本身并没有模板化(不是由它们自己的模板参数列表参数化),而是使用 set
的成员类型 value_type
——它只是 [=15= 的一个 typedef ] 的第一个模板类型参数 Key
——作为 std::initializer
列表的模板参数,我假设这会产生一个足够简单的推导路径,即使没有明确的推导指南也能成功。
我有一个 std::set
允许从迭代器范围中扣除。
#include <iostream>
#include <set>
int main()
{
std::set s1 = {1,2,3,4};
std::set s2(s1.begin(), s1.end());
}
GCC 中的上述程序 failed to compile。
这里std::set
为什么推演失败?
只需使用当前的 GCC 版本(此时为 8.0.0)即可构建。 std::set
的模板推导指南似乎并未在较旧的 GCC 版本的标准库中实现。
std::set
的迭代器构造函数的演绎指南最近才添加到 gcc HEAD 中。
根据 gcc-mirror/gcc
在 GitHub 的说法,std::set
的迭代器构造函数的推导指南是 added and merged to libstdc++-v3 less than two weeks ago、
(Extract from diff for
libstdc++-v3/include/bits/stl_set.h
)+#if __cpp_deduction_guides >= 201606 + + template<typename _InputIterator, + typename _Compare = + less<typename iterator_traits<_InputIterator>::value_type>, + typename _Allocator = + allocator<typename iterator_traits<_InputIterator>::value_type>, + typename = _RequireInputIter<_InputIterator>, + typename = _RequireAllocator<_Allocator>> + set(_InputIterator, _InputIterator, + _Compare = _Compare(), _Allocator = _Allocator()) + -> set<typename iterator_traits<_InputIterator>::value_type, + _Compare, _Allocator>; + + template<typename _Key, typename _Compare = less<_Key>, + typename _Allocator = allocator<_Key>, + typename = _RequireAllocator<_Allocator>> + set(initializer_list<_Key>, + _Compare = _Compare(), _Allocator = _Allocator()) + -> set<_Key, _Compare, _Allocator>; + + template<typename _InputIterator, typename _Allocator, + typename = _RequireInputIter<_InputIterator>, + typename = _RequireAllocator<_Allocator>> + set(_InputIterator, _InputIterator, _Allocator) + -> set<typename iterator_traits<_InputIterator>::value_type, + less<typename iterator_traits<_InputIterator>::value_type>, + _Allocator>; + + template<typename _Key, typename _Allocator, + typename = _RequireAllocator<_Allocator>> + set(initializer_list<_Key>, _Allocator) + -> set<_Key, less<_Key>, _Allocator>; + +#endif
这很自然地解释了为什么模板参数推导对于早期版本的 gcc 的迭代器构造函数的模板化 set
失败,例如7.2.0。如果使用当前的 gcc trunk (gcc HEAD 8.0.0 20171103 (experimental)) the deduction guides above are available,并且迭代器构造函数的模板参数推导也成功。
至于为什么模板参数推导在 gcc 7.2.0 中已经成功用于 std::initializer_list
构造函数(没有推导指南;指南也在上面的提交中添加),正如在 @JohnZwinck deleted answer,这些构造函数本身并没有模板化(不是由它们自己的模板参数列表参数化),而是使用 set
的成员类型 value_type
——它只是 [=15= 的一个 typedef ] 的第一个模板类型参数 Key
——作为 std::initializer
列表的模板参数,我假设这会产生一个足够简单的推导路径,即使没有明确的推导指南也能成功。