我想通过为我的自定义容器(std
之外)添加std::size
和std::empty
的模板特化来扩展std
命名空间。
我有两个问题:
std::size
和std::empty
constexpr
?据我所知,只有std::array
的大小和空虚才能在编译时知道堆栈上的数组,而std::vector
和{{1}等其他容器则不然。 }。那么,当std::map
替换为std::size
作为模板参数时,std::empty
和std::vector
如何工作?std
和std::size
的模板特化扩展std::empty
用于我的自定义容器,但编译器无法推断出专门的模板方法。有人可以解释我做错了吗?我的代码 [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; }
答案 0 :(得分:2)
- 我尝试使用std :: size和std :: empty的模板特化为我的自定义容器扩展std,但是编译器无法推断出专门的模板方法。有人可以解释我做错了吗?
醇>
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。
所以你的功能不是专业化。
因此,除非您在班级中添加widget::size()
声明,否则您无法在std
中专门化该功能。
答案 1 :(得分:1)
为什么
std::size
和std::empty
constexpr
?
对于功能模板,constexpr
仅表示如果可能,结果函数将为constexpr
。并不意味着它对所有实例都是constexpr
。在std::vector
的情况下,这意味着std::size
的特定实例化将不会。
我尝试使用
std::size
和std::empty
的模板特化为我的自定义容器扩展std,但编译器无法推断出专门的模板方法。
这是因为您尝试提供的std::size
和std::empty
版本具有不同的返回类型。标准返回类型为decltype(c.size())
/ decltype(c.empty())
。您没有提供size()
或empty()
成员函数,因此这不可行。只需使用标准名称。
答案 2 :(得分:1)
扩展std::size
的正确方法不是通过专业化。
相反,您应该在与您的类型相同的命名空间中定义一个自由函数size
(可选择作为内联friend
)。
然后
using std::size;
std::cout << size( your_container ) << "\n";
工程;并且用{C}或your_container
容器替换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
。