如何使用static_assert检查模板化函数的迭代器参数的元素类型?

Joh*_* H. 1 c++ templates iterator static-assert type-traits

我有一个带有输出迭代器参数的函数的模板.我如何使用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
}
Run Code Online (Sandbox Code Playgroud)

T.C*_*.C. 5

OutputIterators不需要具有值类型; 它们很value_type可能是void,实际上是void标准库中的纯输出迭代器.

在您检查的原始问题中output_iterator_tag,但您不应该.有许多完全可变的迭代器具有不同的类别.例如,std::vector<int>::iterator类别random_access_iterator_tag.

相反,请直接检查适用表达式的格式良好.所有Iterator小号必须支持*r++r,并且除了OutputIterator小号必须支持*r = o,r++*r++ = o,所以:

template<class...>
struct make_void { using type = void; };

template<class... Ts>
using void_t = typename make_void<Ts...>::type;

template<class Iter, class U, class = void>
struct is_output_iterator_for : std::false_type {};

template<class Iter, class U>
struct is_output_iterator_for<
    Iter, U, 
    void_t<decltype(++std::declval<Iter&>()),
           decltype(*std::declval<Iter&>() = std::declval<U>()),
           decltype(*std::declval<Iter&>()++ = std::declval<U>())>> : std::true_type {};
Run Code Online (Sandbox Code Playgroud)

  • @ 0x49重点是输出迭代器没有值类型.`static_assert(is_output_iterator_for <OutputIter,int> :: value,"msg");` (2认同)