我想确定某件事是否是一个容器。现在我正在对格式化为具有类型和分配器的容器进行测试。我的最终目标是学习如何编写容器模板,当包含自身层时,可以允许直接迭代其最内层元素。例如。如果有一个容器包含3个容器,每个容器包含3个容器,每个容器包含3个元素,我希望能够基于循环遍历一个范围内的所有27个元素。区分某个东西是直接包含元素的容器还是包含元素容器(或容器的容器容器......元素的容器),使用SFINAE来检查元素是否具有迭代器,这似乎是确定{{{ 1}}函数应该将迭代器返回到元素或所述元素的begin()
函数的结果。如果我可以迈出第一步,我想把这个逻辑包含在编写我的容器中,但是我无法编译它:
begin()
我该如何解决这个问题?
答案 0 :(得分:5)
您对某个容器是否是容器的定义似乎完全取决于它是否具有iterator
内部类。
我认为,这与任何启发式一样好,但我们可以选择。
在大多数情况下,如果使用类完成SFINAE
更简单,而不是尝试使用函数实现SFINAE
,例如is_container()
。将is_container()
放入课程会产生以下教科书SFINAE
解决方案:
#include <vector>
#include <string>
#include <iostream>
#include <type_traits>
template<typename ...>
using void_t=void;
template<typename T, class=void> struct is_container : std::false_type {};
template<typename T>
struct is_container<T, void_t<typename T::iterator>> : std::true_type {};
int main()
{
std::cout << is_container<int>::value << std::endl;
std::cout << is_container<std::vector<int>>::value << std::endl;
return 0;
}
现在,一个相关的问题是,是否有更好的方法来检查某件事是否是一个容器。无论您选择哪种启发式方法,调整基于类的测试都是微不足道的,而不是基于函数的测试。例如,如果您想要考虑某个容器是否是容器,如果它同时具有iterator
和const_iterator
内部类,则只需要更改一行:
template<typename T>
struct is_container<T, void_t<typename T::iterator,
typename T::const_iterator>> : std::true_type {};