我对元编程完全不熟悉,我有一些问题。
我想编写一个具有不同内部表示的容器,如果传递的Container
具有Random Access Iterator
,则使用不同的算法。但是,我不知道如何检查它。
更新:现在我正在尝试使用以下内容:
template <typename Container>
struct HaveRandomAccessIterator
{
typedef char yes[1];
typedef char no[2];
template <typename C>
static yes& test (typename std::random_access_iterator_tag*);
template <typename>
static no& test (...);
static const bool value = sizeof(test<std::iterator_traits<typename Container::iterator*>::iterator_category*>(0)) == sizeof(yes);
};
然而它给了我std :: list的真正价值,并且我得到编译错误,因为在那种情况下我使用operator []
有人可以解释我如何正确检查?
答案 0 :(得分:5)
您的HaveRandomAccessIterator
模板过于复杂,有更简单的方法可以达到相同的效果。
基于迭代器类型更改算法的一种标准方法是tag-dispatch:
//First, a helper type alias
template<typename Container>
using IteratorCategoryOf =
typename std::iterator_traits<typename Container::iterator>::iterator_category;
template<typename Container>
void algorithm(Container &c, std::forward_iterator_tag) {
//do generic version of algorithm
}
template<typename Container>
void algorithm(Container &c, std::random_access_iterator_tag) {
//do random-access version of algorithm
}
template<typename Container>
void algorithm(Container &c) {
algorithm(
c,
IteratorCategoryOf<Container>());
}
或者,您可以通过std::enable_if
使用SFINAE。我怀疑这是你的目标,但HaveRandomAccessIterator
可以用std::is_base_of
来编写,这更简单:
template<typename Container>
using HaveRandomAccessIterator =
std::is_base_of<
std::random_access_iterator_tag,
IteratorCategoryOf<Container>>;
template<
typename Container,
typename std::enable_if<!HaveRandomAccessIterator<Container>::value>::type * = nullptr>
void algorithm(Container &c) {
//do generic version of algorithm
}
template<
typename Container,
typename std::enable_if<HaveRandomAccessIterator<Container>::value>::type * = nullptr>
void algorithm(Container &c) {
//do random-access version of algorithm
}
如果需要C ++ 03兼容性,则可以使用继承而不是类型别名,以及std::enable_if
和std::is_base_of
的强制对应。
答案 1 :(得分:1)
应该是:
static yes& test (typename std::iterator_traits<typename C::iterator*>::random_access_iterator_tag*);
SFINAE以这种方式工作。
另外,我发现以下更优雅:
struct yes{};
struct no {};
enum { value = std::is_same<yes, [test-here]>::value };