std::set 演绎指南不符合我的预期
std::set deduction guides don't work as I'd expect
我希望推导指南能够正确推导下面示例中的类型,但它们 don't:
#include <set>
struct Foo { };
bool cmp(const Foo&, const Foo& );
std::set my_set({Foo{}, Foo{}}, cmp);
编译器错误(gcc/clang 显示相似的诊断):
In file included from /opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/x86_64-linux-gnu/bits/c++allocator.h:33,
from /opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/bits/allocator.h:46,
from /opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/bits/stl_tree.h:64,
from /opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/set:60,
from <source>:1:
/opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/ext/new_allocator.h: In instantiation of 'class __gnu_cxx::new_allocator<bool(const Foo&, const Foo&)>':
/opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/bits/alloc_traits.h:634:11: recursively required by substitution of 'template<class _Alloc> struct std::__is_allocator<_Alloc, std::__void_t<typename _Alloc::value_type, decltype (declval<_Alloc&>().allocate(long unsigned int{}))> > [with _Alloc = std::allocator<bool(const Foo&, const Foo&)>]'
/opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/bits/alloc_traits.h:634:11: required by substitution of 'template<class _Alloc> using _RequireAllocator = typename std::enable_if<std::__is_allocator<_Alloc>::value, _Alloc>::type [with _Alloc = std::allocator<bool(const Foo&, const Foo&)>]'
/opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/bits/stl_set.h:938:5: required by substitution of 'template<class _InputIterator, class _Compare, class _Allocator, class, class, class> std::set(_InputIterator, _InputIterator, _Compare, _Allocator)-> std::set<typename std::iterator_traits<_Iter>::value_type, _Compare, _Allocator> [with _InputIterator = bool (*)(const Foo&, const Foo&); _Compare = std::less<bool(const Foo&, const Foo&)>; _Allocator = std::allocator<bool(const Foo&, const Foo&)>; <template-parameter-1-4> = void; <template-parameter-1-5> = std::less<bool(const Foo&, const Foo&)>; <template-parameter-1-6> = <missing>]'
<source>:7:36: required from here
/opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/ext/new_allocator.h:96:7: error: 'const _Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::const_reference) const [with _Tp = bool(const Foo&, const Foo&); __gnu_cxx::new_allocator<_Tp>::const_pointer = bool (*)(const Foo&, const Foo&); __gnu_cxx::new_allocator<_Tp>::const_reference = bool (&)(const Foo&, const Foo&)]' cannot be overloaded with '_Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::reference) const [with _Tp = bool(const Foo&, const Foo&); __gnu_cxx::new_allocator<_Tp>::pointer = bool (*)(const Foo&, const Foo&); __gnu_cxx::new_allocator<_Tp>::reference = bool (&)(const Foo&, const Foo&)]'
96 | address(const_reference __x) const _GLIBCXX_NOEXCEPT
| ^~~~~~~
/opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/ext/new_allocator.h:92:7: note: previous declaration '_Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::reference) const [with _Tp = bool(const Foo&, const Foo&); __gnu_cxx::new_allocator<_Tp>::pointer = bool (*)(const Foo&, const Foo&); __gnu_cxx::new_allocator<_Tp>::reference = bool (&)(const Foo&, const Foo&)]'
92 | address(reference __x) const _GLIBCXX_NOEXCEPT
| ^~~~~~~
Compiler returned: 1
在我看来,这似乎暗示编译器没有使用采用初始化列表的构造函数,而是试图将其视为 2 迭代器版本(当然,也许我没有正确阅读)。
这可能是什么原因造成的?是我误读了演绎指南还是其他原因?
这可能是一个 compiler/library 错误,因为小变体有效:
明确 initializer_list
(Demo):
std::set my_set(std::initializer_list<Foo>{Foo{}, Foo{}}, cmp);
正在添加分配器(Demo):
std::set my_set({Foo{}, Foo{}}, cmp, std::allocator<Foo>{});
使用函子 (Demo):
struct MyComparer
{
bool operator()(const Foo&, const Foo&) const;
};
std::set my_set({Foo{}, Foo{}}, MyComparer{});
并且更改库(libc++ 与 libstdc++)给出了不同的结果 Demo 额外的分配器变体。
我希望推导指南能够正确推导下面示例中的类型,但它们 don't:
#include <set>
struct Foo { };
bool cmp(const Foo&, const Foo& );
std::set my_set({Foo{}, Foo{}}, cmp);
编译器错误(gcc/clang 显示相似的诊断):
In file included from /opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/x86_64-linux-gnu/bits/c++allocator.h:33,
from /opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/bits/allocator.h:46,
from /opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/bits/stl_tree.h:64,
from /opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/set:60,
from <source>:1:
/opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/ext/new_allocator.h: In instantiation of 'class __gnu_cxx::new_allocator<bool(const Foo&, const Foo&)>':
/opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/bits/alloc_traits.h:634:11: recursively required by substitution of 'template<class _Alloc> struct std::__is_allocator<_Alloc, std::__void_t<typename _Alloc::value_type, decltype (declval<_Alloc&>().allocate(long unsigned int{}))> > [with _Alloc = std::allocator<bool(const Foo&, const Foo&)>]'
/opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/bits/alloc_traits.h:634:11: required by substitution of 'template<class _Alloc> using _RequireAllocator = typename std::enable_if<std::__is_allocator<_Alloc>::value, _Alloc>::type [with _Alloc = std::allocator<bool(const Foo&, const Foo&)>]'
/opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/bits/stl_set.h:938:5: required by substitution of 'template<class _InputIterator, class _Compare, class _Allocator, class, class, class> std::set(_InputIterator, _InputIterator, _Compare, _Allocator)-> std::set<typename std::iterator_traits<_Iter>::value_type, _Compare, _Allocator> [with _InputIterator = bool (*)(const Foo&, const Foo&); _Compare = std::less<bool(const Foo&, const Foo&)>; _Allocator = std::allocator<bool(const Foo&, const Foo&)>; <template-parameter-1-4> = void; <template-parameter-1-5> = std::less<bool(const Foo&, const Foo&)>; <template-parameter-1-6> = <missing>]'
<source>:7:36: required from here
/opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/ext/new_allocator.h:96:7: error: 'const _Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::const_reference) const [with _Tp = bool(const Foo&, const Foo&); __gnu_cxx::new_allocator<_Tp>::const_pointer = bool (*)(const Foo&, const Foo&); __gnu_cxx::new_allocator<_Tp>::const_reference = bool (&)(const Foo&, const Foo&)]' cannot be overloaded with '_Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::reference) const [with _Tp = bool(const Foo&, const Foo&); __gnu_cxx::new_allocator<_Tp>::pointer = bool (*)(const Foo&, const Foo&); __gnu_cxx::new_allocator<_Tp>::reference = bool (&)(const Foo&, const Foo&)]'
96 | address(const_reference __x) const _GLIBCXX_NOEXCEPT
| ^~~~~~~
/opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/ext/new_allocator.h:92:7: note: previous declaration '_Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::reference) const [with _Tp = bool(const Foo&, const Foo&); __gnu_cxx::new_allocator<_Tp>::pointer = bool (*)(const Foo&, const Foo&); __gnu_cxx::new_allocator<_Tp>::reference = bool (&)(const Foo&, const Foo&)]'
92 | address(reference __x) const _GLIBCXX_NOEXCEPT
| ^~~~~~~
Compiler returned: 1
在我看来,这似乎暗示编译器没有使用采用初始化列表的构造函数,而是试图将其视为 2 迭代器版本(当然,也许我没有正确阅读)。
这可能是什么原因造成的?是我误读了演绎指南还是其他原因?
这可能是一个 compiler/library 错误,因为小变体有效:
明确
initializer_list
(Demo):std::set my_set(std::initializer_list<Foo>{Foo{}, Foo{}}, cmp);
正在添加分配器(Demo):
std::set my_set({Foo{}, Foo{}}, cmp, std::allocator<Foo>{});
使用函子 (Demo):
struct MyComparer { bool operator()(const Foo&, const Foo&) const; }; std::set my_set({Foo{}, Foo{}}, MyComparer{});
并且更改库(libc++ 与 libstdc++)给出了不同的结果 Demo 额外的分配器变体。