Const converting std containers - c++

Consider that I have a std::vector.
std::vector<int> blah;
blah.push_back(1);
blah.push_back(2);
I now want to pass the vector somewhere and disallow modifying the contents of the objects its contains while still allowing to modify the container when able:
// Acceptable use:
void call_something() {
std::vector<int> blah;
blah.push_back(1);
blah.push_back(2);
// Currently, compiler error because of mismatching types
something(blah);
}
void something(std::vector<const int>& blah)
{
// Auto translates to 'const int'
for ( auto& i : blah ) {
// User cannot modify i.
std::cout << i << std::endl;
}
blah.push_back(blah.size()); // This should be acceptable
blah.emplace_back(); // This should be acceptable
return;
}
// Unacceptable use:
void something_else(const std::vector<int>& blah)
{
// Because of const vector, auto translates to 'const int'
for ( auto& i : blah ) {
std::cout << i std::endl;
}
blah.push_back(blah.size()); // This will present an unacceptable compiler error.
blah.emplace_back(); // This will present an unacceptable compiler error.
return;
}
Is there an easy way to do this?

To enable the operations you wish to allow while preventing the others, you need to take a fine-grained approach to your function's interface. For example, if your calling code were to pass const iterators (begin and end) as well as a back inserter (or custom back emplacer functor), then exactly the subset of operations you showed would be possible.
template <class Iter, class F>
void something(Iter begin, Iter end, F&& append)
{
using value_type = typename std::iterator_traits<Iter>::value_type;
std::copy(begin, end, std::ostream_iterator<value_type>(std::cout, "\n"));
append(std::distance(begin, end));
append();
return;
}
That said I don't find your examples particularly compelling. Do you have a real scenario in which you must maintain mutable elements, pass a mutable container to a function, yet treat the passed elements as immutable?

There is no easy way to do this. One way would be to wrap a vector in a type that exposes only the functionality that you want to allow. For instance
template<typename T, typename A = std::allocator<T>>
struct vector_wrap
{
using iterator = typename std::vector<T, A>::const_iterator;
using const_iterator = typename std::vector<T, A>::const_iterator;
using size_type = typename std::vector<T, A>::size_type;
vector_wrap(std::vector<T, A>& vec)
: vec_(&vec)
{}
void push_back(T const& value) { vec_->push_back(value); }
void push_back(T&& value) { vec_->push_back(std::move(value)); }
size_type size() { return vec_->size(); }
iterator begin() const { return vec_->cbegin(); }
iterator end() const { return vec_->cend(); }
private:
std::vector<T, A> *vec_;
};
Since the above implementation only stores a pointer to the vector it wraps, you'll have to ensure that the lifetime of the vector is longer than that of vector_wrap.
You'll have to modify something and something_else so that they take a vector_wrap<int> as argument. Since vector_wrap::begin and vector_wrap::end return const_iterators, you'll not be allowed to modify existing elements within the for statement.
Live demo

Related

Function to find duplicate values after applying a function

I'd like a function in C++ which finds an item in a collection which has the same value of function(key) as another item in the collection.
e.g.
std::set<int> ints = {1, -1, 3};
// Finds an item in the set with the same absolute value as
// another item.
int* dupe = find_duplicates(ints, [](int x) { return std::abs(x); });
// Should print -1 or 1
if (dupe != 0) std::cout << "Found dupe: " << *dupe << std::endl;
However, I'm having trouble even writing the function signature for this method.
In Java it'd be something like static Integer findDuplicates<T, U>(Iterable<T>, Function<T, U> func).
In C++ I've got as far as the following, but it doesn't compile:
template<template <typename T> Collection, typename U>
T* find_duplicates(
const Collection<T>& collection,
const std::function<U(T)>& func) { ... }
The error I get is error: 'T' does not name a type.
Any pointers? (I'd also be interested in a way to get around the use of the "raw" pointer to T*, but that's probably better for a separate question)
In your example, T is unrecognizable and virtually useless. You should introduce the type T earlier and then use it to specify the Collection, like so:
template<typename T, template <typename> typename Collection, typename U>
T* find_duplicates(const Collection<T>& collection,
const std::function<U(T)>& func)
{
// some logic here
}
Also: notice that you missed a single typename before the Collection, as I pointed out in a comment previously. The above example is adjusted for that suggestion.
For your specific example, something like this should work,
#include <iostream>
#include <set>
#include <algorithm>
using namespace std;
int main() {
std::set<int> ints = {1, -1, 3};
auto dupe = std::find_if(ints.begin(),ints.end(),[&](const int& first){
return std::find_if(ints.begin(),ints.end(),[&](const int& second) {
// so a the same value isn't checked against itself..
if (&first == &second) return false;
return std::abs(first) == std::abs(second);
}) != ints.end();
} );
if (dupe != ints.end()) std::cout << "Found dupe: " << *dupe << std::endl;
}
Demo
Don't be so picky about your function parameter types. You don't really need collection to be a class template specialization, just something you can iterate over (which could even be a C-style array). func just needs to be invokable, and forcing it to be a std::function object can be less efficient than directly using a function pointer or lambda, because of the type erasure std::function adds and then resolves.
So a working declaration could be
template <typename Collection, typename Func>
auto find_duplicates(Collection& collection, const Func& func)
-> typename std::iterator_traits<decltype(std::begin(collection))>::value_type*;
I would do:
#include <utility>
#include <iterator>
#include <set>
// Calling with an rvalue collection would be bad news.
template <typename Collection, typename Func>
void find_duplicates(Collection&&, const Func&) = delete;
template <typename Collection, typename Func>
auto find_duplicates(Collection& collection, const Func& func)
-> typename std::iterator_traits<decltype(std::begin(collection))>::value_type*
{
auto iter = std::begin(collection);
using value_type = typename std::iterator_traits<decltype(iter)>::value_type;
auto ptr_compare = [&func](value_type* p, value_type* q)
{ return func(*p) < func(*q); };
std::set<value_type*, decltype(ptr_compare)> iter_set{ptr_compare};
for (; iter != std::end(collection); ++iter) {
auto insert_result = iter_set.insert(std::addressof(*iter));
if (!insert_result.second)
return *insert_result.first;
}
return nullptr;
}
Sometimes a raw pointer really is the answer. It implies the value might be null, and that the pointer has no ownership relation to the object. In this case, not using the pointer after it's invalidated by modifying or destroying the container is up to the caller, but it has the usual pointer-to-container-element invalidation semantics which depend on the container details.
This won't work with std::vector<bool> or any other pseudo-container where *collection.begin() has a "proxy" type. If you want to support those and can use C++17 std::optional or boost::optional, you could return an optional<value_type> instead of a raw pointer, though this will make a copy of the returned duplicated value. If you can't use those or a copy is undesirable, maybe write a template class iter_or_null<InputIter> that contains an iterator, has operator* and operator-> that just call the iterator's operators, and satisfies the NullablePointer concept.
You're actually being too restrictive with your template. You want your template to take any container for which std::begin and std::end are defined, and any function object that can accept an instance of whatever the container contains. In the template world, you just accept any type, use it the way you would like to, and if the caller doesn't provide a compatibly-typed object, they will get a compilation error.
Further, there's no need to use std::function - it will end up potentially allocating memory when you can just accept the function object as a parameter with a deduced type.
With C++14, auto-deduced return types and auto parameters to lambdas allow you to write very generic code. Here's my solution. It returns an iterator into the container pointing to the first duplicate found, or std::end(c) if no duplicate is found.
#include <algorithm>
#include <cmath>
#include <iterator>
#include <iostream>
#include <set>
template<typename C, typename F>
auto find_duplicates(const C & c, const F & func)
{
return std::find_if(std::begin(c), std::end(c), [&](const auto & first) {
return std::any_of(std::begin(c), std::end(c), [&](const auto & second) {
return &first != &second && func(first) == func(second);
});
});
}
int main()
{
std::set<int> s{1, 3, -1};
auto const iter = find_duplicates(s, [](int x) { return std::abs(x); });
if (iter != std::end(s))
{
std::cout << "Duplicate found: " << *iter << '\n';
}
}
EDIT: I just noticed you specified the C++11 tag. It's only a little more complicated in C++11:
template<typename C, typename F>
auto find_duplicates(const C & c, const F & func) -> decltype(std::begin(c))
{
using ContainedType = decltype(*std::begin(c));
return std::find_if(std::begin(c), std::end(c), [&](const ContainedType & first) {
return std::any_of(std::begin(c), std::end(c), [&](const ContainedType & second) {
return &first != &second && func(first) == func(second);
});
});
}

Moving in range-based loop in generic C++ code?

Imagine that you have this generic pseudo-code:
template<typename Iterable>
void f(Iterable&& iterable)
{
...
}
We want to handle rvalue and lvalue references to iterable objects1, and the idea is that the function handles the container performing operations element by element.
It is plausible that we want to forward the reference specification of the container to the elements. In other words, if iterable is an rvalue reference, the function will have to move the elements from the container.
Using C++17, I would do
auto [begin, end] = [&] {
if constexpr(std::is_lvalue_reference_v<Iterable>)
return std::array{std::begin(iterable),
std::end(iterable)};
else
return std::array{
std::make_move_iterator(std::begin(iterable)),
std::make_move_iterator(std::end(iterable))};
}();
std::for_each(begin, end, [&](auto&& element)
{
...
});
Obviously, this is not the best code to maintain2, error prone and probably not so easy to optimize for the compiler.
My question is: it could be possible, for future C++ standards, to introduce the concept of forwarding range-based loops? It would be nice if this
for(auto&& el : std::move(iterable))
{
...
}
could handle el as rvalue reference. In this way, this would be possible:
template<typename Iterable>
void f(Iterable&& iterable)
{
for(auto&& el : std::forward<Iterable>(iterable))
{
/*
* el is forwarded as lvalue reference if Iterable is lvalue reference,
* as rvalue reference if Iterable is rvalue reference
*/
external_fun(std::forward<decltype(el)>(el));
}
}
I am concerned about code-breaking changes, but at the same time I am not able to think about situations in which passing a rvalue reference as argument of a range based loop is expected to work without moving objects.
As suggested, I tried to write down how I would change the 6.5.4 section of the standard. The draft can be read at this address.
Do you think that it would be possible to introduce this feature without introducing serious issues?
1Checked with C++20 concepts or static_asserts
2And it's quite worse without C++17
This won't work. Fundamentally there are two kinds of things you can iterate over: those that own the elements, and those that don't. For non-owning ranges, the value category of the range is immaterial. They don't own their elements and so you can't safely move from them. The range-based for loop must work with both kind of ranges.
There are also corner cases to consider (e.g., proxy iterators). The range-based for loop is basically syntax sugar that imposes only a very minimal set of requirements on the thing being iterated over. The benefit is that it can iterate over lots of things. The cost is that it doesn't have much room to be clever.
If you know that the iterable in fact owns its elements (so that moving is safe), then all you need is a function that forwards something according to the value category of some other thing:
namespace detail {
template<class T, class U>
using forwarded_type = std::conditional_t<std::is_lvalue_reference<T>::value,
std::remove_reference_t<U>&,
std::remove_reference_t<U>&&>;
}
template<class T, class U>
detail::forwarded_type<T,U> forward_like(U&& u) {
return std::forward<detail::forwarded_type<T,U>>(std::forward<U>(u));
}
You may add a wrapper, something like:
template <typename T> struct ForwardIterable;
template <typename T> struct ForwardIterable<T&&>
{
ForwardIterable(T&& t) : t(t) {}
auto begin() && { return std::make_move_iterator(std::begin(t)); }
auto end() && { return std::make_move_iterator(std::end(t)); }
T& t;
};
template <typename T> struct ForwardIterable<T&>
{
ForwardIterable(T& t) : t(t) {}
auto begin() { return std::begin(t); }
auto end() { return std::end(t); }
auto begin() const { return std::begin(t); }
auto end() const { return std::end(t); }
T& t;
};
template <typename T>
ForwardIterable<T&&> makeForwardIterable(T&& t)
{
return {std::forward<T>(t)};
}
And then
for(auto&& el : makeForwardIterable(std::forward(iterable)))
{
// ...
}
your suggestion will introduce breaking changes. Assume this piece of code:
vector<unique_ptr<int>> vec;
for (int i = 0; i < 10; ++i)
vec.push_back(make_unique<int>(rand()%10));
for (int i = 0; i < 2; ++i) {
for (auto &&ptr : move(vec))
cout << (ptr ? *ptr : 0) << " ";
cout << endl;
}
With current standard, it'll print two same lines
Write a simple range type. It stores two iterators and exposes begin() and end().
Write a move_range_from(Container&&) function that returns a range of move iterators.
Write move_range_from_if<bool>(Container&&) that creates a range or moves from the range conditionally.
Support lifetime extension in both.
template<typename Iterable>
void f(Iterable&& iterable) {
auto move_from = std::is_rvalue_reference<Iterable&&>{};
for(auto&& e: move_range_from_if< move_from >(iterable) ) {
}
}
does what you want.
This supports both ranges (non-owning) and containers and doesn't require a language extension. And it doesn't break existing code.
The lifetime extension feature is so you can call these functions with prvalues; without it, for(:) loops don't lifetime extend arguments to the loop target function call.

generic iterators to access elements of vectors without using Templates c++

I am creating a function which should take as input iterators to vector
for example:
vector<int> a;
foo(a.begin(),a.end())
The vector can hold any type.
Now the simple way to do this is using templates
template <typename Iterator>
void foo(Iterator first, Iterator last) {
for (Iterator it = first; it!=last; ++it) {
cout << *it;
}
}
I want to know if there is a way to achieve the same functionality without using templates. Since using Templates would force me to include these functions in Header file of a public API which I don't want to. So I wanted to know is there an alternate way to access the iterators without using Templates.
There are ways not to include the implementation in header files but they are not clean to implement (for instance you should know in advance the instantiations). Read here for more info about this issue:
Why can’t I separate the definition of my templates class from its declaration and put it inside a .cpp file?
How can I avoid linker errors with my template functions?
For instance in:
foo.h
#ifndef HI_
#define HI_
template<class Iterator>
void foo(Iterator first, Iterator last);
#endif
foo.cpp
#include "stack.h"
using namespace std;
template<class Iterator>
void foo(Iterator first, Iterator last) {
for (Iterator it = first; it != last; ++it) {
cout << *it << " ";
}
}
template
void foo( std::vector<int>::iterator first, std::vector<int>::iterator last);
template
void foo( std::vector<double>::iterator first, std::vector<double>::iterator last);
Now you can use foo function only for double and int. Other types won't link.
Hope this helps.
This is a long answer. The short answer is "type erasure"; go learn about it.
The long answer is two answers. First I cover "do you just want to be able to iterate over contiguous ints?". Then you want span. This is a really simple form of type erasure that forgets what the exact container is you are working on so long as it is contiguous and over T.
The second answer is if you actually need to deal with multiple types (not just int) and multiple kinds of containers (not just contiguous ones).
The two answers are separated by a line.
The span concept (see gsl::span) is designed for pretty much this reason. It itself is a template (over the type you are working with), but it will be a concrete instance of a template in most interfaces.
Here is a toy version of it:
template<class T>
struct span_t {
T* b = 0;
T* e = 0;
T* begin() const { return b; }
T* end() const { return e; }
span_t(span_t const&)=default;
span_t& operator=(span_t const&)=default;
span_t()=default;
span_t( T* s, T* f ):b(s),e(f) {}
span_t( T* s, std::size_t l):span_t(s, s+l){}
template<std::size_t N>
span_t( T(&arr)[N] ):span_t(arr, N) {}
std::size_t size() const { return end()-begin(); }
bool empty() const { return begin()==end(); }
T& front() const { return *begin(); }
T& back() const { return *(std::prev(end()); }
T* data() const { return begin(); }
span_t without_front( std::size_t N=1 ) const {
return {std::next( begin(), (std::min)(N, size()) ), end()};
}
span_t without_back( std::size_t N=1 ) const {
return {begin(), std::prev(end(), (std::min)(N, size()) )};
}
};
we can augment it with conversion operators
namespace details {
template<template<class...>class Z, class, class...Ts>
struct can_apply:std::false_type{};
template<class...>using void_t=void;
template<template<class...>class Z, class...Ts>
struct can_apply<Z, void_t<Z<Ts...>>, Ts...>:std::true_type{};
}
template<template<class...>class Z, class...Ts>
using can_apply = details::can_apply<Z,void,Ts...>;
template<class C>
using dot_data_r = decltype( std::declval<C>().data() );
template<class C>
using dot_size_r = decltype( std::declval<C>().size() );
template<class C>
using can_dot_data = can_apply< dot_data_r, C >;
template<class C>
using can_dot_size = can_apply< dot_size_r, C >;
can_dot_data detects via SFINAE if .data() is valid to do on an object of type C.
Now we add a constructor:
template<class T,
std::enable_if_t<
can_dot_data<T&>{}
&& can_dot_size<T&>{}
&& !std::is_same<std::decay_t<T>, span_t>{}
, int
> =0
>
span_t( T&& t ): span_t( t.data(), t.size() ) {}
which covers std::vector and std::string and std::array.
Your function now looks like:
void foo(span_t<int> s) {
for (auto&& e:s)
std::cout << s;
}
}
with use:
std::vector<int> a;
foo(a);
now, this only works for contiguous containers of a specific type.
Suppose this is not what you want. Maybe you do need to solve this for a myriad of types, and you don't want to expose everything in the header.
Then what you need to do is known as type erasure.
You need to work out what minimal set of operations you need from the provided types. Then you need to write wrappers that "type erase" these operations down to "typeless" operations.
This goes in the header, or in another helper header.
In the interface of the function, or in a header intermediate helper, you take the incoming types and do the type erasure, then pass the type-erased types into the "real" implementation.
An example of type erasure is std::function. It takes almost anything that can be invoked with a fixed signature, and turns it into a single type-erased type. Everything except how to copy, destroy and invoke an instance of the type is "forgotten" or erased.
For your case:
template <typename Iterator>
void foo(Iterator first, Iterator last) {
for (Iterator it = first; it!=last; ++it) {
cout << *it;
}
}
I see two things that need to be erased down to; iteration, and printing.
struct printable_view_t {
void const* data = 0;
void(*print_f)(std::ostream& os, void const*) = 0;
explicit operator bool()const{return data;}
printable_view_t() = default;
printable_view_t(printable_view_t const&) = default;
template<class T,
std::enable_if_t<!std::is_same<T, printable_view_t>{}, int> =0
>
printable_view_t( T const& t ):
data( std::addressof(t) ),
print_f([](std::ostream& os, void const* pv){
auto* pt = static_cast<T const*>(pv);
os << *pt;
})
{}
std::ostream& operator()(std::ostream& os)const {
print_f(os, data);
return os;
}
friend std::ostream& operator<<(std::ostream& os, printable_view_t p) {
return p(os);
}
};
printable_view_t is an example of type-erasing "I can be printed".
void bar( printable_view_t p ) {
std::cout << p;
}
void test_bar() {
bar(7);
bar(3.14);
bar(std::string("hello world"));
}
The next thing we'd have to do is type erase iteration. This is harder, because we want to type erase iteration over iterating over a printable_view_t type.
Type erasing foreach is a tad easier, and often more efficient.
template<class View>
struct foreach_view_t {
void* data = 0;
void(*func)( std::function<void(View)>, void* ) = 0;
explicit operator bool()const{return data;}
foreach_view_t() = default;
foreach_view_t(foreach_view_t const&) = default;
template<class T,
std::enable_if_t<!std::is_same<std::decay_t<T>, foreach_view_t>{}, int> =0
>
foreach_view_t( T&& t ):
data( const_cast<std::decay_t<T>*>(std::addressof(t)) ),
func([](std::function<void(View)> f, void* pv){
auto* pt = static_cast<std::remove_reference_t<T>*>(pv);
for (auto&& e : *pt)
f(decltype(e)(e));
})
{}
void operator()(std::function<void(View)> f)const{
func(f, data);
}
};
we then daisy chain these together
void foo(foreach_view_t<printable_view_t> x) {
x([](auto p){ std::cout << p; });
}
test code:
std::vector<int> a{1,2,3};
foo(a);
Now much of the header code was "hoisted" into the type erasure types instead of a function template body. But careful choice of the points of type erasure can let you keep what you need from the types precise and narrow, and the logic of how you use those operations private.
As an example, the above code doesn't care where you are printing it to; std::cout was not part of the type erasure.
Live example.
I want to know if there is a way to achieve the same functionality without using templates. [...] I wanted to know is there an alternate way to access the iterators without using Templates.
Yes, if you use C++14, but...
Since using Templates would force me to include these functions in Header file of a public API which I don't want to.
... isn't a useful way for you because it's equivalent to use templates and you have to put it in the header file.
In C++14 you can use a lambda function with auto parameters.
auto foo = [](auto first, auto last)
{ for (auto it = first ; it != last; ++it ) std::cout << *it; };
The autos aren't template (from a formal point of view) but are equivalent and you can't declare foo in the header and develop it in a cpp file.

How to write a C++11 template that can take a const iterator

In responding to this question on CodeReview, I was thinking about how one might write a template function to indicate const-ness of a contained object.
To be specific, consider this templated function
#include <iostream>
#include <numeric>
#include <vector>
template <class It>
typename std::iterator_traits<It>::value_type average(It begin, It end) {
typedef typename std::iterator_traits<It>::value_type real;
real sum = real();
unsigned count = 0;
for ( ; begin != end; ++begin, ++count)
sum += *begin;
return sum/count;
}
int main()
{
std::vector<double> v(1000);
std::iota(v.begin(), v.end(), 42);
double avg = average(v.cbegin(), v.cend());
std::cout << "avg = " << avg << '\n';
}
It takes an iterator and calculates an average based on the contained numbers, but it is guaranteed not to modify the vector through the passed iterators. How does one convey this to a user of the template?
Note that declaring it like this:
template <class It>
typename std::iterator_traits<It>::value_type average(const It begin,
const It end)
doesn't work because it's not the iterator, but the thing the iterator points to, that's const. Do I have to wait for concepts to be standardized?
Note that I don't want to require const iterators, but instead to indicate that they may be safely used here. That is, rather than restricting the caller, I want to convey a promise that my code is making: "I will not modify your underlying data."
template <class ConstIt>
It's that simple. There's nothing to be enforced on the caller side here, as a non-const iterator is also usable for const access, so it's just API documentation, and that's what your choice of parameter identifier is - API documentation.
That does lead on to the question of enforcement on the callee/function side - so it can't be pretending it will only use the iterator for const access then modify elements anyway. Should you care about that, you could accept the parameter using some identifier making it clear it wasn't meant to be used everywhere throughout the function, then create a const_iterator version with a more convenient identifier. That could be tricky as in general you don't know if the iterator type is a member of a container, let alone what that container type is and whether it has a const_iterator too, so some manner of Concepts would indeed be ideal - fingers crossed for C++14. Meanwhile:
have your caller tell you the container type,
write your own traits, OR
write a simple wrapper class that holds an iterator and ensures only const access to the referenced data escapes the interface
This last wrapper approach is illustrated below (not all of the iterator API is implemented so flesh out as needed):
template <typename Iterator>
class const_iterator
{
public:
typedef Iterator iterator_type;
typedef typename std::iterator_traits<Iterator>::difference_type difference_type;
// note: trying to add const to ...:reference or ..:pointer doesn't work,
// as it's like saying T* const rather than T const* aka const T*.
typedef const typename std::iterator_traits<Iterator>::value_type& reference;
typedef const typename std::iterator_traits<Iterator>::value_type* pointer;
const_iterator(const Iterator& i) : i_(i) { }
reference operator*() const { return *i_; }
pointer operator->() const { return i_; }
bool operator==(const const_iterator& rhs) const { return i_ == rhs.i_; }
bool operator!=(const const_iterator& rhs) const { return i_ != rhs.i_; }
const_iterator& operator++() { ++i_; return *this; }
const_iterator operator++(int) const { Iterator i = i_; ++i_; return i; }
private:
Iterator i_;
};
Sample usage:
template <typename Const_Iterator>
void f(const Const_Iterator& b__, const Const_Iterator& e__)
{
const_iterator<Const_Iterator> b{b__}, e{e__}; // make a really-const iterator
// *b = 2; // if uncommented, compile-time error....
for ( ; b != e; ++b)
std::cout << *b << '\n';
}
See it running at ideone.com here.
You may add some traits to see if the iterator is a const_iterator:
template <typename IT>
using is_const_iterator =
std::is_const<typename std::remove_reference<typename std::iterator_traits<IT>::reference>::type>;
And then use something like:
template <typename IT>
typename
std::enable_if<is_const_iterator<IT>::value,
typename std::iterator_traits<It>::value_type
>::type average(It begin, It end);
But this will avoid the use of iterator which are convertible to const_iterator.
So it will be better to restrict iterator when const is forbidden (as in std::sort)
It takes an iterator and calculates an average based on the contained numbers, but it is guaranteed not to modify the vector through the passed iterators. How does one convey this to a user of the template?
You could use SFINAE to disable the template when non-const iterators are passed, but that would be an unnecessary limitation.
Another way is to accept ranges instead of iterators. This way you could write:
template <class Range>
typename Range::value_type average(Range const& range);
The user can pass a container or iterator range in there.
You could try always dereferencing the iterator through some function deref().
template <typename It>
typename ::std::remove_reference<typename ::std::iterator_traits<It>::reference>::type const&
deref(It it)
{
return *it;
}
Which would guarantee the underlying value will not be modified.

Why does ostream_iterator need to explicitly declare the type of objects to output?

In current C++, the class ostream_iterator was designed like the following:
// excerpted from the standard C++
template<class T, ...>
class ostream_iterator
{
public:
ostream_iterator(ostream_type&);
...
ostream_iterator<T,...>& operator =(const T&);
...
};
To me, this design is suboptimal. Because the user must specify the type T when declaring an ostream_iterator like this: ostream_iterator<int> oi(cout); In fact, cout can take any type of object as its argument, rather than only one type. This is an obvious restriction.
// Below is my own version
// doesn't need any template parameter here
class ostream_iterator
{
public:
ostream_iterator(ostream_type&);
...
// define a template member function which can take any type of argument and output it
template<class T>
ostream_iterator<T,...>& operator =(const T&);
...
};
Now, we can use it as follows:
ostream_iterator oi(cout);
I think it is more generic and more elegant than
ostream_iterator<int> oi(cout);
Am I right?
The simple answer is that iterator have associated types and ostream_iterator conceptually violates the concept of an iterator by requiring a value_type even when it is not necessary. (This is basically #pts's answer)
What you are proposing is related to the idea behind the new "transparent operators", such as the new std::plus<void>. Which consist in having a special instantiation whose member function has a delayed type deduction.
It is also backward compatible because void is not a useful instantiation to begin with. Moreover the void parameter is also the default. For example template<T = void> struct std::plus{...} is the new declaration.
A possible implementation of a transparent ostream_iterator
Going back of std::ostream_iterator, an important test is whether we want to make it work with std::copy as std::ostream_iterator is usually used:
std::vector<int> v = {...};
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
The technology for a transparent std::ostream_iterator is not there yet, because this fails:
std::copy(v.begin(), v.end(), std::ostream_iterator<void>(std::cout, " "));
To make this work, one can explicitly define the void instance. (This completes #CashCow 's answer)
#include<iterator>
namespace std{
template<>
struct ostream_iterator<void> :
std::iterator<std::output_iterator_tag, void, void, void, void>
{
ostream_iterator(std::ostream& os, std::string delim) :
os_(os), delim_(delim)
{}
std::ostream& os_;
std::string delim_;
template<class T> ostream_iterator& operator=(T const& t){
os_ << t << delim_;
return *this;
}
ostream_iterator& operator*(){return *this;}
ostream_iterator& operator++(){return *this;}
ostream_iterator& operator++(int){return *this;}
};
}
Now this works:
std::copy(v.begin(), v.end(), std::ostream_iterator<void>(std::cout, " "));
Moreover, if we convince the standard committee to have a default void parameter (as they did with with std::plus):
template<class T = void, ...> struct ostream_iterator{...}, we could go a step further and omit the parameter altogether:
std::copy(v.begin(), v.end(), std::ostream_iterator<>(std::cout, " "));
The root of the problem and a possible way out
Finally, in my opinion the problem might also be conceptual, in STL one expects an iterator to have a definite value_type associated even if it is not necessary like here. In some sense ostream_iterator violates some concepts of what is an iterator.
So there are two things that are conceptually wrong in this usage: 1) when one copies one expects to know the type of the source (container value_type) and target types 2) one is not copying anything in the first place!. In my opinion there is a double design mistake in this typical usage. There should be a std::send that works with a template shift << operators directly, instead of making = redirect to << as ostream_iterator does.
std::send(v.begin(), v.end(), std::cout); // hypothetical syntax
std::send(v.begin(), v.end(), std::ostream_receiver(std::cout, " ")); // hypothetical syntax
std::send(v.begin(), v.end(), 'some ostream_filter'); // hypothetical syntax
(The last argument should fulfill some kind of Sink concept).
** Using std::accumulate instead and a possible implementation of
std::send **
From a conceptual point of view, sending objects to a stream is more of an "accumulate" operation than a copy operator, so in principle std::accumulate should be a more suitable candidate, besides we don't need "target" iterators for it.
The problem is that std::accumulate wants to make copies of every object that is being accumulated, so this doesn't work:
std::accumulate(e.begin(), e.end(), std::cout,
[](auto& sink, auto const& e){return sink << e;}
); // error std::cout is not copiable
To make it work we need to do some reference_wrapper magic:
std::accumulate(e.begin(), e.end(), std::ref(std::cout),
[](auto& sink, auto const& e){return std::ref(sink.get() << e);}
);
Finally, the code can be simplified by having the equivalent of std::plus for the shift operator, in modern C++ this should look like this IM:
namespace std{
template<class Sink = void, class T = void>
struct put_to{
std::string delim_;
using sink_type = Sink;
using input_type = T;
Sink& operator()(Sink& s, T const& t) const{
return s << t << delim_;
}
};
template<>
struct put_to<void, void>{
std::string delim_;
template<class Sink, class T>
Sink& operator()(Sink& s, T const& t){
return s << t;
}
template<class Sink, class T>
std::reference_wrapper<Sink> operator()(std::reference_wrapper<Sink> s, T const& t){
return s.get() << t << delim_;
}
};
}
Which can be used as:
std::accumulate(e.begin(), e.end(), std::ref(std::cout), std::put_to<>{", "});
Finally we can define:
namespace std{
template<class InputIterator, class Sink>
Sink& send(InputIterator it1, InputIterator it2, Sink& s, std::string delim = ""){
return std::accumulate(it1, it2, std::ref(s), std::put_to<>{delim});
}
}
Which can be used as
std::send(e.begin(), e.end(), std::cout, ", ");
Finally, there is no dilemma about the type of any output_iterator here.
It appears you could be right.
Let's see if we can construct an ostream_iterator that does not need a template argument.
The iterator works by copying values into it, so *iter = x; ++iter;
The iterator cheats by making operator* return itself and ++iter also returning itself without changing any state. The "magic" is in the operator= which performs the output.
The "cout" must be a class member of type ostream*. It needs to be a pointer as iterators must be assignable, thus we assign the member (call it os) to the address of the stream passed in.
So we would overload operator= this way:
template< typename T >
our_ostream_iterator& operator=( const T& t )
{
(*os) << t;
if( delim )
(*os) << delim;
return *this;
}
Note that the templatised operator= should not oveload operator=(our_ostream_iterator const&) which is more specialised than the template.
You would still want a template on the element type so we will call that our_basic_ostream_iterator
ostream_iterator would still remain a template class on its element type. Thus:
template< typename E, typename TR=char_traits<E> >
class our_basic_ostream_iterator : public std::iterator< /*traits here*/ >
{
public:
typedef E element_type;
typedef TR traits_type;
typedef basic_ostream< E, TR > stream_type;
private:
stream_type * os;
const E* delim;
public:
our_basic_ostream_iterator( stream_type s, const E* d = nullptr ) :
os( &s ), delim( d )
{
}
our_basic_ostream_iterator& operator++() { return *this; }
our_basic_ostream_iterator operator++(int) { return *this; }
our_basic_ostream_iterator& operator*() { return *this; }
template< typename T >
our_basic_ostream_iterator& operator=( const T& t ); // as above
};
and then of course
typedef our_basic_ostream_iterator<char> our_ostream_iterator;
typedef our_basic_ostream_iterator<wchar_t> our_wostream_iterator;
The drawback of all of this though is that the above does not conform to all the properties of iterators such that it could be passed to any algorithm / class that requires a forward iterator. Why? Because such an algorithm should be able to invoke iterator_traits to extract the element type and the class above does not contain an element type.
It would lead to compile-time errors in the algorithm that is using your iterator and would potentially be hard to track down the reason why.
I think the reason is that it has other members also. Obviously the entire set of member functions need to be consistent in their behavior for a given set of T and other template arguments.
There's danger in operator < being instantiated for a set of template arguments which is different from what is used to instantiate operator * or operator++
Hence, the individual methods are not template themselves and rather the entire class is a template so ensure uniform T and other template arguments.
Yes, you are right. It would be more flexible as you suggest. However, the way it's designed fits more closely to how STL uses iterators: one iterator type for data type (T).