简体   繁体   中英

Why does deduction fail for std::set in GCC?

I have a std::set which allows deduction from an iterator range.

#include <iostream>
#include <set>

int main() 
{
   std::set s1 = {1,2,3,4}; 
   std::set s2(s1.begin(), s1.end());
}

The above program failed to compile in GCC.

Why does deduction fail for std::set here?

Just take the current GCC version (8.0.0 at this time) and it will build. The template deduction guide for std::set just doesn't seem to be implemented in the older GCC version's stdlib.

Deduction guides for the iterators constructors of std::set was only recently added to gcc HEAD.

According to gcc-mirror/gcc at GitHub, the deduction guides for std::set 's iterators constructor(s) was 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 

This naturally explains why template argument deduction fails for the templated set by iterator(s) constructors for earlier versions of gcc, eg 7.2.0. If using the current gcc trunk ( gcc HEAD 8.0.0 20171103 (experimental) ) the deduction guides above are available , and the template argument deduction is successful also for the iterator(s) constructors.

As for why the template argument deduction is successful already in gcc 7.2.0 for the std::initializer_list constructors (without deduction guides; guides that was also added in the commit above), as was somewhat explained in @JohnZwinck deleted answer , these constructors are not templated themselves (not parameterized by their own template parameter list), but use set 's member type value_type —which is simply a typedef of the set 's first template type parameter Key —as template argument to the std::initializer list, which I would assume results in a simple enough deduction path to succeed even without and explicit deduction guide.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM