确保模板参数是容器的机制是什么?
或者,如何根据其参数是否为容器来对类/函数进行不同的专业化?
另一种方法是使用boost::spirit::traits::is_container<>
mpl::true_
如果T
定义了以下嵌入类型,则返回:value_type
、iterator
、size_type
和reference
。否则它将返回mpl::false_
。
在 C++03 及更高版本中工作。
测试一个完整的容器是困难和模棱两可的。就我个人而言,当且仅当它拥有其直接内容时,我才将某物视为容器,但这可能与其他人对该术语的使用不一致。
测试可迭代性既不困难也不模棱两可,并且通常是在函数参数中获取对象时要测试的内容。有些可迭代的东西不是非常像容器(例如 C++1y 或 C++1z string_view
)。
在我看来,在 C++11 中,类型 X 的实例 c 是可迭代的 iff:
for( auto&& a : c ) {}
形成良好。为上述选择的措辞意味着您可以使用begin
和end
自由函数重载扩展任何类型以使其可迭代。
如果上述方法可行,一个不错的近似值是测试是否在依赖于参数的启用查找上下文中,std::begin
并std::end
返回具有有效std::iterator_traits<>
.
作为一个速写,我得到这样的东西:
template<typename T, typename=void>
struct is_iterable : std::false_type {};
namespace aux {
using std::begin;
// note: no implementation
template<typename C>
auto adl_begin( C&& c )->decltype( begin( std::forward<C>(c) ) );
using std::end;
// note: no implementation
template<typename C>
auto adl_end( C&& c )->decltype( end( std::forward<C>(c) ) );
}
template<typename T>
struct is_iterable<T,
typename std::enable_if<
std::is_same<
typename std::iterator_traits< typename std::decay<decltype( aux::adl_begin( std::declval<T>() ) )>::type >::iterator_category,
typename std::iterator_traits< typename std::decay<decltype( aux::adl_end( std::declval<T>() ) )>::type >::iterator_category
>::value
>::type
> : std::true_type {};
与此同时,容器很少是统一的。它们最基本的“通用”过程,例如添加元素,在签名和语义上的不同方式彼此不同。 erase(iterator)
和::allocator_type
是类容器结构的两个最常见的特征,但是 astd::array<T,N>
和T[N]
可以说是容器并且没有任何属性。
简而言之,除了它们共同的可迭代性属性之外,容器差异太大,以至于没有一个非常有用的is_container<C>
特征类。相反,您应该计算出您正在寻找的容器的哪些属性(删除元素的能力?插入元素的能力?随机访问?)并测试这些属性。