C++20 Concepts: Element iterable concept - c++

I am trying to create a concept ElementIterable which can determine the type is nested ranges or not. For example, the elements in std::vector<int> is not iterable, but the elements (std::vector<int>) in std::vector<std::vector<int>> is iterable. The idea about using std::iterator_traits<T> comes up in my mind and the experimental code is as following. However, this ElementIterable concept doesn't work as the expected behavior. Is there any idea to fix this ElementIterable concept?
template<typename T>
concept ElementIterable = requires(typename std::iterator_traits<T>::value_type x) // requires-expression
{
x.begin(); // must have `x.begin()`
x.end(); // and `x.end()`
};
The usage of this ElementIterable is here.
template<typename T> requires ElementIterable<T>
void Foo(T input);
template<typename T> requires ElementIterable<T>
void Foo(T input)
{
std::cout << "Element iterable" << std::endl;
}
template<typename T>
void Foo(T input);
template<typename T>
void Foo(T input)
{
std::cout << "Element not iterable" << std::endl;
}
The usage of the function Foo.
int number = 1;
std::vector<decltype(number)> vector1;
vector1.push_back(number);
Foo(vector1); // Element not iterable
std::vector<decltype(vector1)> vector2;
vector2.push_back(vector1);
Foo(vector2); // Element not iterable
// but expected behaviour is: Element iterable
All suggestions are welcome.

If you want to ask if a type is a range which itself contains a range, that's simply applying the std::range type twice:
template<typename T>
concept nested_range = std::ranges::range<T> && std::ranges::range<std::ranges::range_value_t<T>>
range_value_t extracts the value_type from the iterator type of the range. Here's a live example.

Well, the problem is std::iterator_traits<T>. The argument for iterator_traits is supposed to be an iterator type. Meanwhile, you want the concept to be applicable unto containers. Since std::iterator_traits is designed to be SFINAE friendly, and it's unlikely a container will satisfy enough of the legacy iterator concept, it's more than likely std::iterator_traits<T> has no members when you check your concept. That leads to the concept not being satisfied.
Why not rely on the concepts in the ranges header? It has a handy utility to obtain the value type of a type that satisfies the range concept
#include <ranges>
template<typename T>
concept ElementIterable = requires(std::ranges::range_value_t<T> x)
{
x.begin(); // must have `x.begin()`
x.end(); // and `x.end()`
};
Or, slightly more robust and without reinventing standard traits
template<typename T>
concept ElementIterable = std::ranges::range<std::ranges::range_value_t<T>>;

C++20 concepts can be as dumb (as in, text replacing) as you need them to be. In your case, simple template duck typing should do the job by checking for what you need to exist, ie iterator functions in the results of your type's iterator functions.
With that in mind, you can try something like this:
template<typename T>
concept ElementIterable = requires(T x)
{
x.begin()->begin();
x.end()->end();
};

Related

is it possible (and how) to add a type contract check for C++ template function parameter?

For example, I want to implement my own generic sort function, I want to require the type that would be passed in to be Indexable, and the element inside would be Comparable
template <typename Cont>
**type_check: Cont is Indexable, Cont::Element is Comparable**
void my_sort(Cont& cont){
// do sorting work
}
When I do my_sort(vector<int>{1,6,5,4}) would be okay
But when do my_sort(linkedlist<int>{1,6,5,4}) would fail me at Compile/Runtime, because linkedlist is not Indexable.
So is there a way to do such kind of type contract programming?
P.S. I am in C++ 11 environment, but any Solution in later version of C++ is also welcomed
With SFINAE you can do something like:
template <typename Cont>
auto my_sort(Cont& cont)
-> decltype(cont[42], // Indexable
void(), // That void to avoid evil overload of operator comma
std::declval<Cont::Element>() < std::declval<Cont::Element>(), // Comparable
void()) // That final void for the return type of sort
{
// do sorting work
}
std::enable_if is an alternative (to the decltype) if you have the traits ready.
As mentioned in the comments, once the Concepts TS makes its way into the C++ standard, you'll be able to do this with something like:
template <typename T>
concept Sortable = requires(T t) {
{ t[0] < t[0] } -> bool
};
template <Sortable Cont>
my_sort(Cont& cont) {
// do sorting work
}
Live Demo
An older version of the Concepts TS is implemented by GCC with the -fconcepts flag, but it won't be in the standard until C++20. Until then, you can make do with SFINAE tricks:
template <typename Cont>
std::enable_if_t<std::is_convertible_v<decltype(std::declval<Cont>()[0] < std::declval<Cont>()[0]), bool>>
my_sort(Cont& cont) {
// ...
}
This will fail to compile if, for a given Cont c, c[0] < c[0] is either not valid or not convertible to bool.
Live Demo

Type-safe template function which takes iterators

I'm writing different sort functions, which take two iterators and sort sequence. I would like to implement them for any kind of vector and make them typesafe, like this:
template <typename T>
void itsort(std::vector<T>::iterator begin, std::vector<T>::iterator end)
{
// code
}
But due to errors I'm only able to implement something type-unsafe:
template <typename T>
void itsort(T begin, T end)
{
// code
}
How to implement type-safe template function, which takes two vector iterators?
PS: Currently there is no need in comparator, all sorts work with different types of numbers.
Determining if something is an iterator of a vector is hard, and mostly pointless.
The type of vector iterators are extremely free under the standard. They can even be naked pointers in some implementations.
What more, the type of the vector that produces the iterator might not be deducible from the iterator. As an example, a std::vector<int, some_allocator>::iterator might be a different, or the same type, as a std::vector<int>::iterator. They could both be int*, or they could be some class wrapped around a pointer. They could be the same type, or different types. (The technique of using the same type for different container types is called SCARY iterators if you want to find discussion about it).
In general, you cannot determine if a given iterator is a vector iterator.
You can write code that will fail if the given iterator is not a random-access iterator, and deduce the type T. First, a bit of boilerplate to make the access to iterator_traits a bit less verbose:
namespace iterators {
template<class It>
using iterator_category =
typename std::iterator_traits<It>::iterator_category;
template<class It>
using value_type =
typename std::iterator_traits<It>::value_type;
}
now we do this:
template<class It>
void itsort(It begin, It end)
{
using T = iterator::value_type<It>;
using category = iterator::iterator_category<It>;
static_assert(
std::is_base_of<std::random_access_iterator_tag, category>::value, "This function only supports random-access iterators"
);
}
this "fails late", in that the error does not occur at the time of overload resolution (SFINAE), but it does check your types for you.
You also have access to the underlying value type of your iterators.
Doing this in a SFINAE friendly way is difficult, because iterator_traits is not mandated to be SFINAE friendly, and iterator_traits is the mandated way to determine the traits of an iterator. As a concrete example, void* often matches the empty iterator_traits for pointers, but then it fails because it isn't an iterator.
seems you are looking for something like this:
#include <iostream>
#include <vector>
#include <list>
#include <iterator>
template< typename T >
void itsort(T, T, std::bidirectional_iterator_tag)
{
std::cout << "itsort called for bidirectional iterator\n";
}
template <typename T>
void itsort(T, T, std::random_access_iterator_tag)
{
std::cout << "itsort called for random-access iterator\n";
}
template< typename T >
void alg(T first, T last)
{
itsort(first, last, typename std::iterator_traits<T>::iterator_category());
}
int main()
{
std::vector<int> v;
alg(v.begin(), v.end());
std::list<int> l;
alg(l.begin(), l.end());
}

Check if a variable type is iterable?

Is there any way to check if an arbitrary variable type is iterable?
So to check if it has indexed elements or I can actually loop over it's children? (Use foreach for example?)
Is it possible to create a universal template for that?
I've found techniques for other programming languages while searching for it. Yet still have to find out how to do this in C++.
You may create a trait for that:
namespace detail
{
// To allow ADL with custom begin/end
using std::begin;
using std::end;
template <typename T>
auto is_iterable_impl(int)
-> decltype (
begin(std::declval<T&>()) != end(std::declval<T&>()), // begin/end and operator !=
void(), // Handle evil operator ,
++std::declval<decltype(begin(std::declval<T&>()))&>(), // operator ++
void(*begin(std::declval<T&>())), // operator*
std::true_type{});
template <typename T>
std::false_type is_iterable_impl(...);
}
template <typename T>
using is_iterable = decltype(detail::is_iterable_impl<T>(0));
Live example.
cpprefence has an example answering your question. It is using SFINAE, here is a slightly modified version of that example (in case the content of that link gets changed over time):
template <typename T, typename = void>
struct is_iterable : std::false_type {};
// this gets used only when we can call std::begin() and std::end() on that type
template <typename T>
struct is_iterable<T, std::void_t<decltype(std::begin(std::declval<T&>())),
decltype(std::end(std::declval<T&>()))
>
> : std::true_type {};
// Here is a helper:
template <typename T>
constexpr bool is_iterable_v = is_iterable<T>::value;
Now, this is how it can be used
std::cout << std::boolalpha;
std::cout << is_iterable_v<std::vector<double>> << '\n';
std::cout << is_iterable_v<std::map<int, double>> << '\n';
std::cout << is_iterable_v<double> << '\n';
struct A;
std::cout << is_iterable_v<A> << '\n';
Output:
true
true
false
false
Having said that, all it checks is, the declaration of begin() const and end() const, so accordingly, even following is verified as an iterable:
struct Container
{
void begin() const;
void end() const;
};
std::cout << is_iterable_v<Container> << '\n'; // prints true
You can see these pieces together here
If you are under the umbrella of C++11 and beyond, one usual way of SFINAE checking that works when you have to specialize for just one property, is the following one:
template<class T, class = decltype(<expression that must compile>)>
inline constexpr bool expression_works(int) { return true; }
template<class>
inline constexpr bool expression_works(unsigned) { return false; }
template<class T, bool = expression_works<T>(42)>
class my_class;
template<class T>
struct my_class<T, true>
{ /* Implementation when true */ };
template<class T>
struct my_class<T, false>
{ /* Implementation when false */ };
The trick is as follow:
When the expression doesn't work, only the second specialization will be instantiated, because the first will fail to compile and sfinae plays out. So you get false.
When the expression works, both overloads are candidate, so I have to force a better specialization. In this case, 42 has type int, and thus int is a better match than unsigned, getting true.
I take 42 because it's the answer to everything, inspired by Eric Niebler's range implementation.
In your case, C++11 has the free functions std::begin and std::end that works for arrays and containers, so the expression that must work is:
template<class T, class = decltype(std::begin(std::declval<T>()))
inline constexpr bool is_iterable(int) { return true; }
template<class>
inline constexpr bool is_iterable(unsigned) { return false; }
If you need more generality, a way to express that something is iterable could also include user-defined types that brings their own overloads for begin and end, so you need to apply some adl here:
namespace _adl_begin {
using std::begin;
template<class T>
inline auto check() -> decltype(begin(std::declval<T>())) {}
}
template<class T, class = decltype(_adl_begin::check<T>())>
inline constexpr bool is_iterable(int) { return true; }
template<class>
inline constexpr bool is_iterable(unsigned) { return false; }
You can play with this technique to achieve solutions that fits better your actual context.
Yes using this traits class compatible c++03
template<typename C>
struct is_iterable
{
typedef long false_type;
typedef char true_type;
template<class T> static false_type check(...);
template<class T> static true_type check(int,
typename T::const_iterator = C().end());
enum { value = sizeof(check<C>(0)) == sizeof(true_type) };
};
Explanation
check<C>(0) calls check(int,const_iterator) if C::end() exists and returns a const_iterator compatible type
else check<C>(0) calls check(...) (see ellipsis conversion)
sizeof(check<C>(0)) depends on the return type of these functions
finally, the compiler sets the constant value to true or false
See compilation and test run on coliru
#include <iostream>
#include <set>
int main()
{
std::cout <<"set="<< is_iterable< std::set<int> >::value <<'\n';
std::cout <<"int="<< is_iterable< int >::value <<'\n';
}
Output
set=1
int=0
Note: C++11 (and C++14) provides many traits classes but none about iterablility...
See also similar answers from jrok and Jarod42.
This answer is in Public Domain - CC0 1.0 Universal
It depends on what you mean by "iterable". It is a loose concept in C++ since you could implement iterators in many different ways.
If by foreach you're referring to C++11's range-based for loops, the type needs begin() and end() methods to be defined and to return iterators that respond to operator!=,
operator++ and operator*.
If you mean Boost's BOOST_FOREACH helper, then see BOOST_FOREACH Extensibility.
If in your design you have a common interface that all iterable containers inherit from, then you could use C++11's std::is_base_of:
struct A : IterableInterface {}
struct B {}
template <typename T>
constexpr bool is_iterable() {
return std::is_base_of<IterableInterface, T>::value;
}
is_iterable<A>(); // true
is_iterable<B>(); // false
Or if (like me) you hate every SFINAE solution being a big block of dummy struct definitions with ::type and ::value nonsense to wade through, here's an example of using a quick and (very) dirty one-liner:
template <
class Container,
typename ValueType = decltype(*std::begin(std::declval<Container>()))>
static void foo(Container& container)
{
for (ValueType& item : container)
{
...
}
}
The last template argument does multiple things in one step:
Checks to see if the type has a begin() member function, or equivalent.
Checks that the begin() function returns something that has operator*() defined (typical for iterators).
Determines the type that results from de-referencing the iterator, and saves it in case it's useful in your template implementation.
Limitation: Doesn't double-check that there's a matching end() member function.
If you want something more robust/thorough/reusable, then go with one of the other excellent proposed solutions instead.

How to deduce iterator template type, or its template's nested type?

This questions begs a more preparation, so I provide some bits of code first and then the exact question
Assuming I have the following type declared
template<typename T>
struct some_type
{
T t_;
};
which would be constructed with a factory function like so
typedef float numeric_type;
std::vector<std::string> construction_material;
//Push_back of strings in certain form...
std::vector<std::unique_ptr<some_type<numeric_type>> instances;
build_instances(construction_material.begin(), construction_material.end(), back_inserter(instances));
and the construction function would be something like following
template<typename input_iterator, typename output_iterator>
output_iterator build_instances(input_iterator begin, input_iterator end, output_iterator out)
{
for(input_iterator iter = begin; iter != end; ++iter)
{
//This won't work, but to illustrate some ideas...
//build_instance<std::iterator_traits<output_iterator>::value_type>(*iter)
}
//[...]
return *out;
}
template<typename T>
std::unique_ptr<some_type<T>> build_instance(std::string const& material)
{
static_assert(std::is_floating_point<T>::value == true, "The template type needs to be a floating point type.");
std::unique_ptr<some_instance<T>> instance(new some_instance<T>());
//Some processing...
return instance;
}
I know I could change the function to return some container (or perhaps even templatize the container type), like
template<typename input_iterator, typename T>
std::vector<std::unique_type<T>> build_instances(input_iterator begin, input_iterator end,
output_iterator out)
{
//Likewise code to the previous snippets...
return ...
}
The problems I haven't been able to solve are:
Would it be possible -- or impossible -- to use the back_inserter like approach? It looks like being the most flexible for the caller?
How to get a hold on the numeric_type in build_instances body (as in having it through output_iterator) so that it can be used in building the instances one-by-one?
How to ensure the caller knows to wait for the objects wrapped in std::unique_ptrs? An alternative would be just as plain pointers, but I'm not enthuasiastic about that.
There's a similar kind of question with a heading How can I make this template method more elegant? (or: less explicit template parameters required), which takes a container and transforms it to a different type of a container.
Edit
As commented to Jogojapan's comment that currently I transform the input like so
std::transform(construction_material.begin(), construction_material.end(), std::inserter(instances, instances.begin()), build_instance<numeric_type>);
but the subsequent function calls need to be supplied the numeric_type typedef too, which is somewhat cumbersome. I hope to avoid that. It looks I was mistaken, but for the purpose of education and all, would it be possible to further reduce the need to typedef the numeric type and deduce it from the iterator?
An intrusive solution is to let some_type exposes its type parameter, the same way std::unique_ptr<T, D> exposes its first parameter via element_type (which we will need later):
template<typename T>
struct some_type
{
// give it an appropriate meaningful name
using value_type = T;
value_type t_;
};
template<typename input_iterator, typename output_iterator>
output_iterator build_instances(input_iterator begin, input_iterator end, output_iterator out)
{
using pointer_type = typename std::iterator_traits<output_iterator>::value_type;
using value_type = typename pointer_type::element_type::value_type;
return std::transform(begin, end, out, build_instance<value_type>);
}
You can also non-intrusively extract the first template parameter of a template specialization:
template<typename T>
struct first;
template<template<typename...> class Template, typename First, typename... Pack>
struct first<Template<First, Pack...>>> {
using type = First;
};
template<typename T>
using First = typename first<T>::type;
The value_type alias in build_instances would instead become
using value_type = First<typename pointer_type::element_type>;
As a final remark I find it a bit odd that build_instance take a T parameter but constructs instances of some_type<T>. If it took T and constructed instances of T (where perhaps T is restricted to be a specialization of some_type.) This would have spared your problem, too.

begin(), end() annoyance in STL algorithms

I like STL algorithms, and prefer use algorithms rather than usual loops.
Almost all STL algorithms are usually used as:
std::algorithm_name( container.begin(), container.end(), ..... )
container.begin(), container.end() - is one of most popular words pair in my projects.
Does anybody have the same problem?
How do you Guys solve this problem?
What could you propose to avoid this duplication? I see a few ways for solution, but all of them have different limitations (macro usage, not compatible with usual pointers, etc.).
The next C++ standard, C++0X (where X stands for, hopefully, 9) will add the possibility to change from iterator perspective to container perspective. You will be able to do eg.
std::sort(my_vec);
If you cant wait for this I would recommend you to look at: Boost.Range
And if you are a really interested in iterators/ranges I would recommend you to read Andrei's "iterators must go"
Many have encountered this nuisance. Though the iterator concept is exceptionally general, it lacks some usability.
Enter the 'range' concept. It is to be preferred to avoid any code duplication. So if you encounter .begin() and .end() pairs all over the code, it's good practice to create a layer in between the 'iterator-getting' and the actual algorithms.
References:
RangeLib
CodeProject
...
#define ALL(x) (x).begin(), (x).end()
sort(ALL(vec));
First, I don't think it's a big issue. In general, I don't really care about typing a few more characters. readability is more important, and I think begin/end is perfectly readable.
Shorter container names can help though (con.begin() is easier to type than container.begin())
And passing iterators around instead of the container itself means that you don't have to call begin/end more than once in any case.
It's not really something that bothers me.
If it got really bad, I would probably create a bunch of templates for my most commonly used algorithms in a new namespace:
namespace my_ranged_algorithms {
// Metafunction for extracting an appropriate iterator from
// the container type
template <typename T>
struct get_iterator_type_for;
// For vectors
template <typename T>
struct get_iterator_type_for<std::vector<T> > {
typedef typename std::vector<T>::iterator type;
};
template <typename T>
struct get_iterator_type_for<std::vector<T> const> {
typedef typename std::vector<T>::const_iterator type;
};
// For C arrays
template <typename T, size_t N>
struct get_iterator_type_for<T(&)[N]> {
typedef T* type;
};
// Generic begin() and end() wrappers
// For all standard containers
template <typename Cont>
typename get_iterator_type_for<Cont>::type begin(Cont& c) {
return c.begin();
}
template <typename Cont>
typename get_iterator_type_for<Cont>::type end(Cont& c) {
return c.end();
}
// For C arrays
template <typename T, size_t N>
typename get_iterator_type_for<T (&)[N]>::type begin(T (&c)[N]) {
return c;
}
template <typename T, size_t N>
typename get_iterator_type_for<T (&)[N]>::type end(T (&c)[N]) {
return c + N;
}
// Finally, the actual algorithm wrappers
// copy
template <typename Cont, typename OutIter>
OutIter copy(Cont& from, OutIter to) {
return std::copy(begin(from), end(from), to);
}
// remove
template <typename Cont, typename T>
typename get_iterator_type_for<Cont>::type remove(Cont& from, T x) {
return std::remove(begin(from), end(from), x);
}
// etc.
};
Then call them like so:
vector<int> a, b;
using namespace my_ranged_algorithms;
copy(a, back_inserter(b));
b.erase(remove(b, 42), b.end()); // Remember to call erase() after remove()!
This nice presentation [PDF] about a possible future solution to this was recently linked from reddit. it discusses how to fully replace iterators with the range concept.
C++11 has addressed this minor annoyance within the language.
boost::range_ex will solve this before c++0x.
And it's not hard to write a few wrappers yourself in the meantime.