Add static_assert macros, use them in the tests and examples, and add docs for

them.
This commit is contained in:
Zach Laine 2019-08-10 18:34:19 -05:00
parent b7fea24984
commit c0e571d034
10 changed files with 271 additions and 8 deletions

View File

@ -45,6 +45,9 @@
[def _Facade_ Boost.IteratorFacade]
[def _iter_facade_ [classref boost::iterator_facade::iterator_facade `iterator_facade`]]
[def _concept_m_ [macroref BOOST_ITERATOR_FACADE_STATIC_ASSERT_CONCEPT]]
[def _traits_m_ [macroref BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_TRAITS]]
[def _CRTP_ [@https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern CRTP]]
[def _Iterator_ [@https://www.boost.org/doc/libs/release/libs/iterator/doc/index.html Boost.Iterator]]

View File

@ -219,4 +219,7 @@ Consider this good code hygiene. Without this simple check, you'll probably
eventually find yourself looking at an error message with a very long template
instantiation stack.
There's also a macro that can help you check that `std::iterator_traits` is
well-formed and provides the corect types. See _traits_m_.
[endsect]

View File

@ -47,10 +47,11 @@ private:
};
//]
//[ node_iterator_concept_check
#if 201703L < __cplusplus
static_assert(std::forward_iterator<node_iterator>);
#endif
//[ node_iterator_concept_check Equivalent to
// static_assert(std::forward_iterator<node_iterator>), or nothing in C++17
// and earlier.
BOOST_ITERATOR_FACADE_STATIC_ASSERT_CONCEPT(
node_iterator, std::forward_iterator)
//]

View File

@ -22,7 +22,7 @@ template<typename BidiIter>
struct reverse_iterator
: boost::iterator_facade::iterator_facade<
reverse_iterator<BidiIter>,
#if 201703L < __cplusplus
#if 201703L < __cplusplus && defined(__cpp_lib_ranges)
typename std::iterator_traits<BidiIter>::iterator_concept,
#else
typename std::iterator_traits<BidiIter>::iterator_category,

View File

@ -333,8 +333,6 @@ namespace boost { namespace iterator_facade {
// TODO: Compile-fail tests and associated static_asserts in these
// specializations to help catch common errors.
// TODO: Tests that cover iterator_traits for uses of these facades.
/** A specialization of iterator_facade specific to output iterators. */
template<
typename Derived,
@ -861,4 +859,81 @@ namespace boost { namespace iterator_facade {
}}
#ifdef BOOST_ITERATOR_FACADE_DOXYGEN
/** `static_asserts` that iterator type `iter` models concept `concept_name`.
This is useful for checking that an iterator you write using
`iterator_facade` models the right C++ concept.
For example: `BOOST_ITERATOR_FACADE_STATIC_ASSERT_CONCEPT(my_iter,
std::input_iterator)`.
\note This macro exapnds to nothing when `__cpp_lib_concepts` is not
defined. */
#define BOOST_ITERATOR_FACADE_STATIC_ASSERT_CONCEPT(iter, concept_name)
/** `static_asserts` that the types of all typedefs in
`std::iterator_traits<iter>` match the remaining macro parameters. This
is useful for checking that an iterator you write using `iterator_facade`
has the correct iterator traits.
For example: `BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_TRAITS(my_iter,
std::input_iterator_tag, std::input_iterator_tag, int, int &, int *, std::ptrdiff_t)`.
\note This macro ignores the `concept` parameter when `__cpp_lib_concepts`
is not defined. */
#define BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_TRAITS( \
iter, category, concept, value_type, reference, pointer, difference_type)
#else
#define BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_CONCEPT_IMPL( \
iter, concept_name) \
static_assert(concept_name<iter>);
#if 201703L < __cplusplus && defined(__cpp_lib_concepts)
#define BOOST_ITERATOR_FACADE_STATIC_ASSERT_CONCEPT(iter, concept_name) \
BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_CONCEPT_IMPL( \
iter, concept_name)
#else
#define BOOST_ITERATOR_FACADE_STATIC_ASSERT_CONCEPT(iter, concept_name)
#endif
#define BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_TRAITS_IMPL( \
iter, category, value_t, ref, ptr, diff_t) \
static_assert(std::is_same< \
typename std::iterator_traits<iter>::iterator_category, \
category>::value); \
static_assert(std::is_same< \
typename std::iterator_traits<iter>::value_type, \
value_t>::value); \
static_assert( \
std::is_same<typename std::iterator_traits<iter>::reference, ref>:: \
value); \
static_assert( \
std::is_same<typename std::iterator_traits<iter>::pointer, ptr>:: \
value); \
static_assert(std::is_same< \
typename std::iterator_traits<iter>::difference_type, \
diff_t>::value);
#if 201703L < __cplusplus && defined(__cpp_lib_ranges)
#define BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_TRAITS( \
iter, category, concept, value_type, reference, pointer, difference_type) \
static_assert(std::is_same< \
typename std::iterator_traits<iter>::iterator_concept, \
concept>::value); \
BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_TRAITS_IMPL( \
iter, category, value_type, reference, pointer, difference_type)
#else
#define BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_TRAITS( \
iter, category, concept, value_type, reference, pointer, difference_type) \
BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_TRAITS_IMPL( \
iter, category, value_type, reference, pointer, difference_type)
#endif
#endif
#endif

View File

@ -33,6 +33,17 @@ private:
int * it_;
};
BOOST_ITERATOR_FACADE_STATIC_ASSERT_CONCEPT(
basic_bidirectional_iter, std::bidirectional_iterator)
BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_TRAITS(
basic_bidirectional_iter,
std::bidirectional_iterator_tag,
std::bidirectional_iterator_tag,
int,
int &,
int *,
std::ptrdiff_t)
template<typename ValueType>
struct bidirectional_iter : boost::iterator_facade::iterator_facade<
bidirectional_iter<ValueType>,
@ -65,6 +76,28 @@ private:
using bidirectional = bidirectional_iter<int>;
using const_bidirectional = bidirectional_iter<int const>;
BOOST_ITERATOR_FACADE_STATIC_ASSERT_CONCEPT(
bidirectional, std::bidirectional_iterator)
BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_TRAITS(
bidirectional,
std::bidirectional_iterator_tag,
std::bidirectional_iterator_tag,
int,
int &,
int *,
std::ptrdiff_t)
BOOST_ITERATOR_FACADE_STATIC_ASSERT_CONCEPT(
const_bidirectional, std::bidirectional_iterator)
BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_TRAITS(
const_bidirectional,
std::bidirectional_iterator_tag,
std::bidirectional_iterator_tag,
int const,
int const &,
int const *,
std::ptrdiff_t)
#if 0 // TODO: Call ranges algorithms with this.
struct basic_proxy_bidirectional_iter : boost::iterator_facade::iterator_facade<
basic_proxy_bidirectional_iter,

View File

@ -28,6 +28,17 @@ private:
int * it_;
};
BOOST_ITERATOR_FACADE_STATIC_ASSERT_CONCEPT(
basic_forward_iter, std::forward_iterator)
BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_TRAITS(
basic_forward_iter,
std::forward_iterator_tag,
std::forward_iterator_tag,
int,
int &,
int *,
std::ptrdiff_t)
template<typename ValueType>
struct forward_iter : boost::iterator_facade::iterator_facade<
forward_iter<ValueType>,
@ -59,6 +70,28 @@ private:
using forward = forward_iter<int>;
using const_forward = forward_iter<int const>;
BOOST_ITERATOR_FACADE_STATIC_ASSERT_CONCEPT(
forward, std::forward_iterator)
BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_TRAITS(
forward,
std::forward_iterator_tag,
std::forward_iterator_tag,
int,
int &,
int *,
std::ptrdiff_t)
BOOST_ITERATOR_FACADE_STATIC_ASSERT_CONCEPT(
const_forward, std::forward_iterator)
BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_TRAITS(
const_forward,
std::forward_iterator_tag,
std::forward_iterator_tag,
int const,
int const &,
int const *,
std::ptrdiff_t)
#if 0 // TODO: Call ranges algorithms with this.
struct basic_proxy_forward_iter : boost::iterator_facade::iterator_facade<
basic_proxy_forward_iter,

View File

@ -28,6 +28,17 @@ private:
int * it_;
};
BOOST_ITERATOR_FACADE_STATIC_ASSERT_CONCEPT(
basic_input_iter, std::input_iterator)
BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_TRAITS(
basic_input_iter,
std::input_iterator_tag,
std::input_iterator_tag,
int,
int &,
int *,
std::ptrdiff_t)
template<typename ValueType>
struct input_iter : boost::iterator_facade::iterator_facade<
input_iter<ValueType>,
@ -56,6 +67,17 @@ private:
friend struct input_iter;
};
BOOST_ITERATOR_FACADE_STATIC_ASSERT_CONCEPT(
input_iter<int>, std::input_iterator)
BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_TRAITS(
input_iter<int>,
std::input_iterator_tag,
std::input_iterator_tag,
int,
int &,
int *,
std::ptrdiff_t)
using int_input = input_iter<int>;
using const_int_input = input_iter<int const>;
using pair_input = input_iter<std::pair<int, int>>;
@ -89,6 +111,18 @@ private:
friend struct proxy_input_iter;
};
using int_pair = std::pair<int, int>;
BOOST_ITERATOR_FACADE_STATIC_ASSERT_CONCEPT(
proxy_input_iter<int_pair>, std::input_iterator)
BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_TRAITS(
proxy_input_iter<int_pair>,
std::input_iterator_tag,
std::input_iterator_tag,
int_pair,
int_pair,
boost::iterator_facade::proxy_arrow_result<int_pair>,
std::ptrdiff_t)
std::array<int, 10> ints = {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}};
std::array<std::pair<int, int>, 10> pairs = {{
{0, 1},

View File

@ -14,7 +14,7 @@
struct basic_output_iter
: boost::iterator_facade::
iterator_facade<basic_output_iter, std::input_iterator_tag, int>
iterator_facade<basic_output_iter, std::output_iterator_tag, int>
{
basic_output_iter() : it_(nullptr) {}
basic_output_iter(int * it) : it_(it) {}
@ -29,6 +29,16 @@ private:
using output = basic_output_iter;
BOOST_ITERATOR_FACADE_STATIC_ASSERT_CONCEPT(output, std::output_iterator)
BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_TRAITS(
output,
std::output_iterator_tag,
std::output_iterator_tag,
int,
int &,
void,
std::ptrdiff_t)
template<typename Container>
struct back_insert_iter : boost::iterator_facade::iterator_facade<
back_insert_iter<Container>,
@ -60,6 +70,16 @@ private:
using back_insert = back_insert_iter<std::vector<int>>;
BOOST_ITERATOR_FACADE_STATIC_ASSERT_CONCEPT(back_insert, std::output_iterator)
BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_TRAITS(
back_insert,
std::output_iterator_tag,
std::output_iterator_tag,
int,
back_insert &,
void,
std::ptrdiff_t)
std::vector<int> ints = {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}};

View File

@ -32,6 +32,17 @@ private:
int * it_;
};
BOOST_ITERATOR_FACADE_STATIC_ASSERT_CONCEPT(
basic_random_access_iter, std::random_access_iterator)
BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_TRAITS(
basic_random_access_iter,
std::random_access_iterator_tag,
std::random_access_iterator_tag,
int,
int &,
int *,
std::ptrdiff_t)
template<typename ValueType>
struct random_access_iter : boost::iterator_facade::iterator_facade<
random_access_iter<ValueType>,
@ -63,6 +74,28 @@ private:
using random_access = random_access_iter<int>;
using const_random_access = random_access_iter<int const>;
BOOST_ITERATOR_FACADE_STATIC_ASSERT_CONCEPT(
random_access, std::random_access_iterator)
BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_TRAITS(
random_access,
std::random_access_iterator_tag,
std::random_access_iterator_tag,
int,
int &,
int *,
std::ptrdiff_t)
BOOST_ITERATOR_FACADE_STATIC_ASSERT_CONCEPT(
const_random_access, std::random_access_iterator)
BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_TRAITS(
const_random_access,
std::random_access_iterator_tag,
std::random_access_iterator_tag,
int const,
int const &,
int const *,
std::ptrdiff_t)
// TODO: Call ranges algorithms with this.
struct zip_iter : boost::iterator_facade::proxy_iterator_facade<
zip_iter,
@ -93,6 +126,20 @@ private:
int * it2_;
};
using int_pair = std::tuple<int, int>;
using int_refs_pair = std::tuple<int &, int &>;
BOOST_ITERATOR_FACADE_STATIC_ASSERT_CONCEPT(
zip_iter, std::random_access_iterator)
BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_TRAITS(
zip_iter,
std::random_access_iterator_tag,
std::random_access_iterator_tag,
int_pair,
int_refs_pair,
boost::iterator_facade::proxy_arrow_result<int_refs_pair>,
std::ptrdiff_t)
struct int_t
{
int value_;
@ -139,6 +186,20 @@ private:
int * it2_;
};
using int_t_int_pair = std::tuple<int_t, int>;
using int_t_int_refs_pair = std::tuple<int_t &, int &>;
BOOST_ITERATOR_FACADE_STATIC_ASSERT_CONCEPT(
udt_zip_iter, std::random_access_iterator)
BOOST_ITERATOR_FACADE_STATIC_ASSERT_ITERATOR_TRAITS(
udt_zip_iter,
std::random_access_iterator_tag,
std::random_access_iterator_tag,
int_t_int_pair,
int_t_int_refs_pair,
boost::iterator_facade::proxy_arrow_result<int_t_int_refs_pair>,
std::ptrdiff_t)
namespace std {
// Required for std::sort to work with zip_iter. If zip_iter::reference
// were not a std::tuple with builtin types as its template parameters, we