Search code examples
c++templatesc++17stdset

Deduce type of Compare for std::set from constructor arguments


I wanna write simpler syntax when declaring std::set with custom compare:

auto s = std::set({1,3,7,9,2,4},[](int a,int b){return a>b;});

but it does not work out of the box. CLang produces:

/Users/kyb/devel/untitled3/main.cpp:13:14: error: ambiguous deduction for template arguments of 'set'
    auto s = set({1,3,7,9,2,4},[](int a,int b){return a>b;});
             ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/set:531:5: note: candidate function [with _Key = int, _Compare = (lambda at /Users/kyb/devel/untitled3/main.cpp:13:32), _Allocator = std::__1::allocator<int>]
    set(initializer_list<value_type> __il, const value_compare& __comp = value_compare())
    ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/set:547:5: note: candidate function [with _Key = int, _Compare = std::__1::less<int>, _Allocator = (lambda at /Users/kyb/devel/untitled3/main.cpp:13:32)]
    set(initializer_list<value_type> __il, const allocator_type& __a)
    ^
1 error generated.

There is a trick - invade deduction guide:

namespace std::__1{
    template<typename T, typename Compare> set(initializer_list<T> il, const Compare&comp) -> set<T,Compare>;
}

which produces warning:

warning: inline namespace reopened as a non-inline namespace

I believe there is a way to do that in more clean way.

clang --version:

Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.7.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
/V/l/n/new-diag-commands ❯❯❯

Solution

  • I believe there is a way to do that in more clean way.

    Your code snippet above should not be rejected by clang, as is governed by [associative.reqmts]/151 [emphasis mine]:

    A deduction guide for an associative container shall not participate in overload resolution if any of the following are true:

    • (15.1) It has an InputIterator template parameter and a type that does not qualify as an input iterator is deduced for that parameter.
    • (15.2) It has an Allocator template parameter and a type that does not qualify as an allocator is deduced for that parameter.
    • (15.3) It has a Compare template parameter and a type that qualifies as an allocator is deduced for that parameter.

    As of Clang 9, this has been corrected.


    [1] N4659: March 2017 post-Kona working draft/C++17 DIS.