std::size 和 std::empty 的特化与模板不匹配
Specializations of std::size and std::empty do not match the template
我想通过为我的自定义容器(在 std
之外)添加 std::size
和 std::empty
的模板特化来扩展 std
命名空间。
我有两个问题:
- 为什么是
std::size
and std::empty
constexpr
?据我所知,在编译时只能知道 std::array
和堆栈上的数组的大小和空性,而对于其他容器,例如 std::vector
和 std::map
.那么 std::size
和 std::empty
甚至在将 std::vector
替换为模板参数时如何工作呢?
- 我尝试使用自定义容器的
std::size
和 std::empty
模板特化扩展 std
,但编译器无法推断出专用模板方法。有人可以解释我做错了什么吗?
我的代码 [Try it online in Wandbox]:
#include <iterator>
#include <vector>
namespace dummy {
struct Widget {
bool IsEmpty() const noexcept { return m_v.empty(); }
size_t GetSize() const noexcept { return m_v.size(); }
std::vector< int > m_v;
};
}
namespace std {
template<>
constexpr auto empty(const dummy::Widget &widget)
-> decltype(widget.IsEmpty()) {
return widget.IsEmpty();
}
template<>
constexpr auto size(const dummy::Widget &widget)
-> decltype(widget.GetSize()) {
return widget.GetSize();
}
}
int main() {
std::vector< int > ints;
std::size(ints);
}
输出:
prog.cc:15:17: error: no function template matches function template specialization 'empty'
constexpr auto empty(const dummy::Widget &widget)
^
/opt/wandbox/clang-head/include/c++/v1/iterator:1843:16: note: candidate template ignored: substitution failure [with _Cont = dummy::Widget]: no member named 'empty' in 'dummy::Widget'
constexpr auto empty(const _Cont& __c)
^
/opt/wandbox/clang-head/include/c++/v1/iterator:1850:16: note: candidate template ignored: could not match 'type-parameter-0-0 const[_Np]' against 'const dummy::Widget'
constexpr bool empty(const _Tp (&)[_Sz]) noexcept { return false; }
^
/opt/wandbox/clang-head/include/c++/v1/iterator:1854:16: note: candidate template ignored: could not match 'initializer_list<type-parameter-0-0>' against 'const dummy::Widget &'
constexpr bool empty(initializer_list<_Ep> __il) noexcept { return __il.size() == 0; }
^
prog.cc:22:17: error: no function template matches function template specialization 'size'
constexpr auto size(const dummy::Widget &widget)
^
/opt/wandbox/clang-head/include/c++/v1/iterator:1832:16: note: candidate template ignored: substitution failure [with _Cont = dummy::Widget]: no member named 'size' in 'dummy::Widget'
constexpr auto size(const _Cont& __c)
^
/opt/wandbox/clang-head/include/c++/v1/iterator:1839:18: note: candidate template ignored: could not match 'type-parameter-0-0 const[_Np]' against 'const dummy::Widget'
constexpr size_t size(const _Tp (&)[_Sz]) noexcept { return _Sz; }
- I tried to extend the std with template specializations of std::size and std::empty for my custom containers, but the compiler could not deduce the specialized template method. Could someone explain what I do wrong?
std::size
签名为:
template <class C>
constexpr auto size( const C& c ) -> decltype(c.size());
你的不一样:
template<>
constexpr auto size(const dummy::Widget &widget)
-> decltype(widget.GetSize());
decltype(..)
内容不一样,你做SFINAE的方法不一样
所以你的函数不是专业化。
因此,除非您在 class 中添加 widget::size()
声明,否则您无法在 std
.
中特化该函数
Why are std::size
and std::empty
constexpr
?
对于函数模板,constexpr
仅表示如果可能,结果函数将是 constexpr
。这并不意味着所有实例化都是 constexpr
。在 std::vector
的情况下,这意味着 std::size
的特定实例不会。
I tried to extend the std with template specializations of std::size
and std::empty
for my custom containers, but the compiler could not deduce the specialized template method.
那是因为您尝试为其提供专业化的 std::size
和 std::empty
版本具有不同的 return 类型。标准的 return 类型是 decltype(c.size())
/ decltype(c.empty())
。您不提供 size()
或 empty()
成员函数,因此这不可能工作。只需使用标准名称即可。
扩展 std::size
的正确方法不是通过专业化。
相反,您应该在与您的类型相同的命名空间中定义一个自由函数 size
(可选择作为内联 friend
)。
然后
using std::size;
std::cout << size( your_container ) << "\n";
有效; your_container
替换为 C 数组或 std
容器也可以(在通用代码中)。
using std::size
的要求很烦人。您可以解决它:
namespace notstd {
namespace adl_size {
using std::size;
template<class T>
constexpr auto get_size(T const& t)
noexcept( noexcept( size(t) ) )
->decltype( size(t) )
{ return size(t); }
}
template<class T>
constexpr auto size( T const& t )
noexcept( noexcept( ::notstd::adl_size::get_size(t) ) )
-> decltype( ::notstd::adl_size::get_size(t) )
{ return ::notstd::adl_size::get_size(t); }
}
现在 notstd::size( vector )
和 notstd::size( your_container )
和 notstd::size( some_array )
都可以使用,并且不需要在使用前显式添加 using std::size
。
我想通过为我的自定义容器(在 std
之外)添加 std::size
和 std::empty
的模板特化来扩展 std
命名空间。
我有两个问题:
- 为什么是
std::size
andstd::empty
constexpr
?据我所知,在编译时只能知道std::array
和堆栈上的数组的大小和空性,而对于其他容器,例如std::vector
和std::map
.那么std::size
和std::empty
甚至在将std::vector
替换为模板参数时如何工作呢? - 我尝试使用自定义容器的
std::size
和std::empty
模板特化扩展std
,但编译器无法推断出专用模板方法。有人可以解释我做错了什么吗?
我的代码 [Try it online in Wandbox]:
#include <iterator>
#include <vector>
namespace dummy {
struct Widget {
bool IsEmpty() const noexcept { return m_v.empty(); }
size_t GetSize() const noexcept { return m_v.size(); }
std::vector< int > m_v;
};
}
namespace std {
template<>
constexpr auto empty(const dummy::Widget &widget)
-> decltype(widget.IsEmpty()) {
return widget.IsEmpty();
}
template<>
constexpr auto size(const dummy::Widget &widget)
-> decltype(widget.GetSize()) {
return widget.GetSize();
}
}
int main() {
std::vector< int > ints;
std::size(ints);
}
输出:
prog.cc:15:17: error: no function template matches function template specialization 'empty'
constexpr auto empty(const dummy::Widget &widget)
^
/opt/wandbox/clang-head/include/c++/v1/iterator:1843:16: note: candidate template ignored: substitution failure [with _Cont = dummy::Widget]: no member named 'empty' in 'dummy::Widget'
constexpr auto empty(const _Cont& __c)
^
/opt/wandbox/clang-head/include/c++/v1/iterator:1850:16: note: candidate template ignored: could not match 'type-parameter-0-0 const[_Np]' against 'const dummy::Widget'
constexpr bool empty(const _Tp (&)[_Sz]) noexcept { return false; }
^
/opt/wandbox/clang-head/include/c++/v1/iterator:1854:16: note: candidate template ignored: could not match 'initializer_list<type-parameter-0-0>' against 'const dummy::Widget &'
constexpr bool empty(initializer_list<_Ep> __il) noexcept { return __il.size() == 0; }
^
prog.cc:22:17: error: no function template matches function template specialization 'size'
constexpr auto size(const dummy::Widget &widget)
^
/opt/wandbox/clang-head/include/c++/v1/iterator:1832:16: note: candidate template ignored: substitution failure [with _Cont = dummy::Widget]: no member named 'size' in 'dummy::Widget'
constexpr auto size(const _Cont& __c)
^
/opt/wandbox/clang-head/include/c++/v1/iterator:1839:18: note: candidate template ignored: could not match 'type-parameter-0-0 const[_Np]' against 'const dummy::Widget'
constexpr size_t size(const _Tp (&)[_Sz]) noexcept { return _Sz; }
- I tried to extend the std with template specializations of std::size and std::empty for my custom containers, but the compiler could not deduce the specialized template method. Could someone explain what I do wrong?
std::size
签名为:
template <class C>
constexpr auto size( const C& c ) -> decltype(c.size());
你的不一样:
template<>
constexpr auto size(const dummy::Widget &widget)
-> decltype(widget.GetSize());
decltype(..)
内容不一样,你做SFINAE的方法不一样
所以你的函数不是专业化。
因此,除非您在 class 中添加 widget::size()
声明,否则您无法在 std
.
Why are
std::size
andstd::empty
constexpr
?
对于函数模板,constexpr
仅表示如果可能,结果函数将是 constexpr
。这并不意味着所有实例化都是 constexpr
。在 std::vector
的情况下,这意味着 std::size
的特定实例不会。
I tried to extend the std with template specializations of
std::size
andstd::empty
for my custom containers, but the compiler could not deduce the specialized template method.
那是因为您尝试为其提供专业化的 std::size
和 std::empty
版本具有不同的 return 类型。标准的 return 类型是 decltype(c.size())
/ decltype(c.empty())
。您不提供 size()
或 empty()
成员函数,因此这不可能工作。只需使用标准名称即可。
扩展 std::size
的正确方法不是通过专业化。
相反,您应该在与您的类型相同的命名空间中定义一个自由函数 size
(可选择作为内联 friend
)。
然后
using std::size;
std::cout << size( your_container ) << "\n";
有效; your_container
替换为 C 数组或 std
容器也可以(在通用代码中)。
using std::size
的要求很烦人。您可以解决它:
namespace notstd {
namespace adl_size {
using std::size;
template<class T>
constexpr auto get_size(T const& t)
noexcept( noexcept( size(t) ) )
->decltype( size(t) )
{ return size(t); }
}
template<class T>
constexpr auto size( T const& t )
noexcept( noexcept( ::notstd::adl_size::get_size(t) ) )
-> decltype( ::notstd::adl_size::get_size(t) )
{ return ::notstd::adl_size::get_size(t); }
}
现在 notstd::size( vector )
和 notstd::size( your_container )
和 notstd::size( some_array )
都可以使用,并且不需要在使用前显式添加 using std::size
。