Partial template specialization based on lval/rval? - c++

I'm writing an adaptor class to allow me to write this:
for (auto item : ButFirst(myvec)) { ... }
The following class definition works well when, as above, the argument is an lval:
template <typename Container>
class ButFirst {
const Container& container_;
public:
ButFirst(const Container& container) : container_(container) {}
typename Container::const_iterator begin() { return ++(container_.begin()); }
typename Container::const_iterator end() { return container_.end(); }
};
However, I want to also use it when the argument is an rval, as in:
for (auto item : ButFirst(get_vec(3)) { ... }
I would therefore write the following class definition:
template <typename Container>
class ButFirst {
const Container container_;
public:
ButFirst(Container&& container) : container_(std::move(container)) {}
...
};
How can I write one class definition that handles both? Or maybe one class and some partial template specializations?

template <typename Container>
class ButFirst {
Container container_;
public:
ButFirst(Container container) : container_(std::forward<Container>(container)) {}
typename std::decay_t<Container>::const_iterator begin() { return std::next(container_.begin()); }
typename std::decay_t<Container>::const_iterator end() { return container_.end(); }
};
then add deduction guide:
template <typename Container>
ButFirst(Container&&)->ButFirst<Container>;
and ... poof.
Despite appearances this only copies on rvalues.
The forwarding reference in the ButFirst deduction guide deduces Container to be a reference type when you construct it with an lvalue, and Container as a value type when you pass it an rvalue. This is exactly what you want.
And that isn't a coincidence; forwarding references work that way for a reason.
live example.
As an aside, my version of this is a bit different.
I define a range_view type that can be constructed from a range-like, and stores 2 iterators.
range_view methods like begin() are const; range_view is like a pointer, not like a value.
It has methods:
range_view except_front(std::size_t n=1)const;
range_view except_back(std::size_t n=1)const;
range_view only_front(std::size_t n=1)const;
range_view only_back(std::size_t n=1)const;
which clamp n based on how big the range is.
Then:
for(auto item: range_view(container).except_front())
does what yours does.
I consider checking for iterator counting errors and returning empty range in that case well worth the overhead for the reliability I get from it, as that math happens once per loop, not once per iteration.
Also, range_view has ridiculously many other useful uses.

Related

Concepts: require a function on a type without default constructing that type

I need to require of some type A that there exists a function f(A, A::B).
I'm testing that by calling f with instances of A and A::B. Is there a less ostentatious way to test against an instance of the dependent type without requiring default constructible?
template <class Container>
concept CanPutData = requires (Container a)
{
//put(typename Container::data_type{}, a); // overconstrained
put(*reinterpret_cast<typename Container::data_type*>(0), a); // oof
};
void test(CanPutData auto container) {}
template<class Container>
void put(typename Container::data_type const& data, Container& into) {}
template<class Data>
struct data_container { using data_type = Data; };
struct not_default_constructible_data { int& v; };
int main()
{
test(data_container<not_default_constructible_data>{});
return 0;
}
Same way you're already getting a Container without requiring that one to be default constructible: by just sticking it in the parameter list of the requires expression:
template <class Container>
concept CanPutData = requires (Container container, typename Container::data_type data)
{
put(data, container);
};
You can also put Container::data_type in the template parameter list
template <class Container, class DataType = Container::data_type>
concept CanPutData = requires (DataType d, Container a)
{
put(d, a);
};
Demo
The advantage of this form is that when the requires-clause is relatively large, if the Container does not have a data_type member, the compiler will only report that the template parameter list does not satisfy the constraints, rather than output the entire requires clause.

Template class with iterator to a STL container

I want to create a template class which has an iterator of a STL container as a member. That is how far I got:
#include <iostream>
#include <vector>
using namespace std;
template<typename Element, template <class> class StdLibContainer>
struct ClassHoldingAnIteratorToAStandardContainer
{
ClassHoldingAnIteratorToAStandardContainer(){}
typename StdLibContainer<Element*>::iterator std_lib_iterator;
};
int main()
{
vector<int> vec{1,2,3};
ClassHoldingAnIteratorToAStandardContainer<int,vector<int>> holding_iterator_to_vec;
//DOES NOT WORK, compiler says: expected a class template, got ‘std::vector<int>’
return 0;
}
Could you explain the syntax template <typename> class StdLibContainer?
I found it somewhere on stackoverflow. BUt I don't understand it.
How can I create an instance of ClassHoldingAnIteratorToAStandardContainer ? All my attempts failed so far. The compiler always gives the error message: `expected a class template, got ‘std::vector’
In the above example i want to assign holding_iterator_to_vec vec.begin().
template <typename> class is the same as template <class> class. Originally, when templates were introduced, they allowed two equivalent forms:
template<class T> struct Foo {};
// or
template<typename T> struct Foo {};
Do not ask me why! However, the same was not true for template template parameters:
template <template <class> typename T> struct Foo {};
was the only allowed syntax. Apparently, people were unhappy about it, so the syntax was relaxed.
As for your second question, std::vector takes at least two template arguments, data type and allocator. This is why a single argument template doesn't cut it before C++17. After C++17, it would work.
To make it universal, use
template<template <class...> class Container> struct Foo{};
Unless you really need to know the type of the container, I would strongly recommend to keep your ClassHoldingAnIteratorToAStandardContainer independent of the concrete container type. If you just need the iterator, this is simpler and sufficient:
template<typename iterator>
struct iterator_wrapper {
iterator iter;
};
Thats the minimum you need to have an iterator as member :).
I dont really know what you want to use the iterator for, so just for the sake of an example lets add methods that actually use the iterator....
#include <iterator>
#include <vector>
#include <iostream>
template<typename iterator>
struct iterator_wrapper {
using value_type = typename std::iterator_traits<iterator>::value_type;
iterator iter;
bool operator!=(const iterator& other) { return iter != other;}
iterator_wrapper& operator++(){
++iter;
return *this;
}
const value_type& operator*() { return *iter; }
};
template <typename iterator>
iterator_wrapper<iterator> wrap_iterator(iterator it) {
return {it};
}
int main() {
std::vector<int> vec{1,2,3};
auto it = wrap_iterator(vec.begin());
for (;it != vec.end();++it) std::cout << *it;
}
Also there is a problem in your code.
typename StdLibContainer<Element*>::iterator
is for containers of pointers while in main you have ints. If you want to infer the iterator type from the container type then you can do it for example like this:
template <typename container,
typename iterator = typename container::iterator>
iterator_wrapper<iterator> wrap_begin(container& c) {
return {c.begin()};
}
which makes creating an iterator_wrapper as simple as
auto x = wrap_begin(vec);
Note that this answer applies to C++11, in newer standards there are deduction guides that make such make_x methods more or less superfluous afaik.

Does a forward_iterator template class make sense?

The C++ standard library contains the convenient template class std::move_iterator. Given the close relationship between std::move and std::forward, why is there no equivalent std::forward_iterator? Example usage:
template <typename C>
auto foo(C&& values)
{
remove_reference_t<C> result {};
result.reserve(values.size());
std::transform(std::make_forward_iterator<C>(std::begin(values)),
std::make_forward_iterator<C>(std::end(values))),
std::back_inserter(result), Bar());
return result;
}
The idea being I can now use foo like:
std::vector<ComplexType> values {/* lots of values */};
auto copied_fooed = foo(values);
// or
auto moved_fooed = foo(std::move(values));
Without having to write two foos.
I can't answer why such a thing doesn't exist. But it's certainly implementable. Basically, your C type is either an lvalue reference (in which case just pass through the argument) or it's not a reference (in which case, use std::make_move_iterator).
First, let's start with a great addition to any toolkit, almost static if (with minor changes):
namespace detail {
enum class enabler {};
}
template <bool B>
using EnableIf = std::enable_if_t<B, detail::enabler>;
And now we just use SFINAE on the two overloads:
template <typename C,
typename Iterator,
EnableIf<std::is_lvalue_reference<C>::value>...>
Iterator make_forward_iterator(Iterator i)
{
return i;
}
template <typename C,
typename Iterator,
EnableIf<!std::is_lvalue_reference<C>::value>...>
auto make_forward_iterator(Iterator i)
{
return std::make_move_iterator(i);
}
Alternatively, and this is probably simpler, could just tag-dispatch:
namespace detail {
template <typename Iterator>
Iterator make_forward_iterator(Iterator i, std::true_type )
{
return i;
}
template <typename Iterator>
auto make_forward_iterator(Iterator i, std::false_type )
{
return std::make_move_iterator(i);
}
}
template <typename C, typename Iterator>
auto make_forward_iterator(Iterator i) {
return detail::make_forward_iterator(i, std::is_lvalue_reference<C>{});
}
It is a bit more complex than that.
With an owning container, the l/r valueness of the container imply move iterators may be of use.
But for views, this does not work: moving from an rvalue view is destructive of unowned state.
Practically, this means the decision to move or not based on l/r valueness is matter for both the context and value to mutually decide, which makes it tricky.
Range-v3 and concepts may make this easier to reason about.

Naturally ban wrapper classes in C++

So, I found it more natural to work in algorithms with collections, not with pair of iterators. So, I wrote some functions like
template <typename R>
void sort(R& range) {
return std::sort(std::begin(range), std::end(range));
}
And to have possibility to work with parts of collections I've wrote following wrapper class, that just holds pair of iterators.
template <typename T>
class Range{
public:
Range(T begin, T end): begin_(begin), end_(end) {}
const T& begin() {
return begin_;
}
const T& end() {
return end_;
}
private:
T begin_, end_;
};
To that point all is fine. Now I want to have function that copies/(moves if possible) its argument and return new collection.
I wrote something like this:
template <typename R>
R sorted(R range) {
sort(range);
return std::move(range);
}
and that's fine except that if I call it with my wrapper Range class internal collection changed. I do understand that with only iterator type it's generally impossible to retrieve the type of collection to create new one, but I want to at least disallow calling it with this Wrapper.
I do understand that I can use static_assert of enable_if to check if it is of particular Range class and I will do that way unless I will find better way. But I want ban it somehow in more general way, so that similar implementation will fail to compile too.
Any ideas?
You can delete the function like:
template <typename T>
void sorted(const Range<T>& range) = delete;
else you can disallow copy and move of the object, so it can only be used with reference
template <typename T>
class Range{
public:
Range(const Range&) = delete;
Range(Range&&) = delete;
Range& operator =(const Range&) = delete;
Range& operator =(Range&&) = delete;
// previous code
};
I would create a traits class called owning_container. By default it considers arguments that are ranges (you should have a traits class/concept constexpr for that -- if begin(x) in a namespace with using std::begin; returns an iterator, call it a range) and have an allocator (another trait) to be owning (as non-owning ranges usually have no need for an allocator) as well as C arrays and std::arrays as owning (via specialization).
This also allows me to detect rvalue owning containers and move their contents in certain contexts (change their iterators into move iterators) without doing the same to non-owning range views.
As mentioned above, a constexpr pseudo-concept might be better than a traits class, or might be useful to augment it.

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.