【发布时间】:2014-11-05 21:42:21
【问题描述】:
我有一个接受输出迭代器参数的函数模板。如何使用static_assert 检查实例化是否使用了适当的迭代器? (即,它既是一个输出迭代器,又是它分配正确类型的元素。)
#include <iostream>
#include <list>
#include <set>
template <class OutputIter>
void add_ints ( OutputIter iter )
{
static_assert ( something_goes_here,
"Arg must be an output iterator over ints" );
*iter++ = 1;
*iter++ = 2;
*iter++ = 3;
}
main()
{
// Insert iterator will add three elements.
std::set<int> my_set;
add_ints ( std::inserter ( my_set, my_set.end() ) );
for ( int i : my_set ) std::cout << i << "\n";
// Non-insert iterator will overwrite three elements.
std::list<int> my_list ( { 0, 0, 0 } );
add_ints ( my_list.begin() ) );
for ( int i : my_list ) std::cout << i << "\n";
#if 0
// Want nice compile error that container elements are not ints.
std::set<std::string> bad_set;
add_ints ( std::inserter ( bad_set, bad_set.end() ) );
#endif
#if 0
// Want nice compile error that argument is not an iterator.
class Foo {} foo;
add_ints ( foo );
#endif
}
【问题讨论】:
-
使用
iterator_traits<T>::value_type。您应该使用iterator_traits进行当前检查以适应没有嵌套iterator_category类型的类型(不确定这对于OutputIterator 是否可行)。我还认为您应该使用is_base_of而不是is_same来测试迭代器类别。如果有人向您传递了一个仍然满足OutputIterator的所有要求的更精细的迭代器类别,您的代码应该仍然可以工作(尽管目前标准库中不存在这种类型)。 -
OutputIterators 需要仅支持*r = o,而不是r = o。对于某些标准库输出迭代器,取消引用操作是无操作的这一事实仅是这些迭代器的实现细节,您不应该在通用代码中依赖它。检查std::output_iterator_tag通常也不是一个好主意。许多可变迭代器会有不同的标签。 -
@Praetorian 这不是你想要的。对于许多
OutputIterators,iterator_traits<T>::value_type是void。 -
您无法可靠地检测输出迭代器。您可以做的最好的事情是 (1) 断言该参数是某种迭代器(
std::iterator_traits<T>::iterator_category存在),并且 (2) 断言可以通过传递给您的任何内容来分配一个整数。 -
static_assert(std::is_assignable<decltype(*iter),int>(), "Jabberwocky is killing user.")之类的就可以了。
标签: c++ templates iterator typetraits static-assert