Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 549
msc Avatar asked Nov 06 '17 12:11

msc


2 Answers

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.

like image 64
Jodocus Avatar answered Sep 21 '22 14:09

Jodocus


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, e.g. 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.

like image 24
dfrib Avatar answered Sep 19 '22 14:09

dfrib