Consider a large memory container. In this simple example an std::vector<int>:
std::vector v = { 0, 1, 2, 3, 4, 5 };
std::span allows me create a lightweight view over the memory. Now I want to simply print the span:
template<typename T>
void print(std::span<T> span) {
std::cout << '[';
if (span.size())
std::copy(span.begin(), span.end() - 1, std::ostream_iterator<int>(std::cout, ", "));
std::cout << span.back() << "]\n";
}
int main() {
std::vector v = { 0, 1, 2, 3, 4, 5 };
print(std::span{ v });
}
output:
[0, 1, 2, 3, 4, 5]
now I want to make subsets (which is where the std::span actually becomes useful as a view). I can use iterators to specify my range and call this constructor(3) from std::span
template< class It, class End >
explicit(extent != std::dynamic_extent)
constexpr span( It first, End last );
But that doesn't work:
print(std::span{ v.begin() + 2, v.end() }); //error E0289
C++ no instance of constructor matches the argument list argument types are: (std::_Vector_iterator<std::_Vector_val<std::conditional_t<true, std::_Simple_types, std::_Vec_iter_types<int, size_t, ptrdiff_t, int *, const int *, int &, const int &>>>>, std::_Vector_iterator<std::_Vector_val<std::conditional_t<true, std::_Simple_types, std::_Vec_iter_types<int, size_t, ptrdiff_t, int *, const int *, int &, const int &>>>>)
there is the possibility of using the constructor(2) which takes a pointer and size:
print(std::span{ v.data() + 1, 3 }); //-> prints [1, 2, 3]
But that defeats the purpose of iterators.
How can I construct an std::span using iterators? Am I missing something?
full code:
#include <iostream>
#include <vector>
#include <span>
#include <algorithm>
template<typename T>
void print(std::span<T> span) {
std::cout << '[';
if (span.size())
std::copy(span.begin(), span.end() - 1, std::ostream_iterator<int>(std::cout, ", "));
std::cout << span.back() << "]\n";
}
int main() {
std::vector v = { 0, 1, 2, 3, 4, 5 };
print(std::span{ v.begin() + 2, v.end() });
}
until MSVC has implemented the constructor I will be using this make_span function:
template<typename It>
constexpr auto make_span(It begin, It end) {
return std::span<std::remove_pointer_t<It::pointer>>(&(*begin), std::distance(begin, end));
}
Using Visual Studio Community 2019 Version 16.7.5. Configuration: x64, Release. C++ Language Standard = /std:c++latest
You can construct a span using iterators, it has such a constructor (as added by P1394, which you can see in [views.span]):
template< class It, class End >
explicit(extent != std::dynamic_extent)
constexpr span( It first, End last );
It's just that MSVC's standard library doesn't implement it. The program compiles fine on gcc, as expected.
Related
I'd like to iterate over a container (say a std::vector) but not from the beginning. I am basically trying to replicate boost::make_iterator_range(v.begin() + 1, v.end()).
I came up with this:
#include <vector>
#include <iostream>
#include <algorithm>
int main()
{
std::vector<int> v {1, 2, 3};
std::for_each_n(v.begin() + 1, v.size() - 1, [](auto& n)
{
std::cout << n << '\n';
});
}
However this seems like a poor solution. Also it requires C++17 while I am looking for a solution that works in C++14.
Is there a better way to achieve this without the use of third party libraries?
std::for_each is in C++11 and with that you can do:
std::for_each(v.begin() + 1, v.end(), [](auto &n) { ... });
To replicate make_iterator_range you need an object with a begin and end function. Something like this.
template <typename T>
struct iterator_range {
iterator_range(T begin, T end) : m_begin(begin), m_end(end) {}
T begin() {
return m_begin;
}
T end() {
return m_end;
}
T m_begin, m_end;
};
Then we can make our make_iterator_range function that return an iterator_range.
#include <vector>
#include <iostream>
template <typename T>
struct iterator_range {
iterator_range(T begin, T end) : m_begin(begin), m_end(end) {}
T begin() {
return m_begin;
}
T end() {
return m_end;
}
T m_begin, m_end;
};
template <typename T>
auto make_iterator_range(T begin, T end) {
return iterator_range<T>(begin, end);
}
int main()
{
std::vector<int> v {1, 2, 3};
auto range = iterator_range<decltype(v.begin())>(v.begin() + 1, v.end());
for (auto& i : range) {
std::cout << i << '\n';
}
for (auto& i : make_iterator_range(v.begin() + 1, v.end())) {
std::cout << i << '\n';
}
}
Is there a better way to achieve this ...
A solution using ranges (courtesy of cigien in comments):
for (int element : v | ranges::drop_view(1))
A solution using span
for (int element : span(&v[1], v.size() - 1))
Of course, there aren't std::ranges nor std::span until C++20, so unless you want to use a third party implementation, you'll need to write your own.
If you don't want to implement your own libraries, nor can use C++20, nor want to use a third party library, then std::for_each an alternative that is in C++11.
I've been trying to brush up on my C++ knowledge and found this issue I cannot Google for easily.
I've written a function with the following signature:
template <typename Iterator>
Iterator lower_bound(
Iterator left,
Iterator right,
typename Iterator::value_type const& target
) {
//stuff happens here
}
and I'm trying to use it like so:
std::vector<int> odd{1, 2, 3, 4, 5, 6, 7};
int i = 4;
std::cout << std::distance(odd.begin(), lower_bound(odd.begin(), odd.end(), i)) << std::endl;
I'm getting the following compilation error: error: call to 'lower_bound' is ambiguous.
I'm guessing I'm lacking some understanding about how template types are resolved and so would be grateful for any resources that might explain this in a bit more detail.
Here, std::lower_bound is causing the ambiguity. Due to Argument-dependent lookup your function as well as the std version are around.
If you use your own (non-std) iterator type, then you would not face any problem. See the example below (live demo):
#include <vector>
#include <iostream>
template <class T>
struct myIter {
using value_type = T;
myIter(T* const ptr) : ptr(ptr) {};
T& operator*() {return *ptr;};
T* ptr;
};
template <typename Iterator>
Iterator lower_bound(
Iterator left,
Iterator right,
typename Iterator::value_type const& target)
{
return left;
}
int main()
{
std::vector<int> odd{1, 2, 3, 4, 5, 6, 7};
myIter<int> b(&(odd.front())), e(&(odd.back()));
int i = 4;
std::cout << *(lower_bound(b,e, i)) << std::endl; // <- works
// std::cout << *(lower_bound(odd.begin(),odd.end(), i)) << std::endl; // <- compiler error
}
I have a bimap like this:
using MyBimap = boost::bimaps::bimap<
boost::bimaps::unordered_set_of<A>,
boost::bimaps::unordered_set_of<B>>;
I want to construct it from a static initializer list, as it can be done for std::map:
MyBimap map{{a1, b1}, {a2, b2}, {a3, b3}};
Unfortunately, it doesn't work because bimap doesn't support initializer lists, so I tried a workaround. Boost's documentation lists the following constructors:
bimap();
template< class InputIterator >
bimap(InputIterator first,InputIterator last);
bimap(const bimap &);
So I tried the second one, like this:
std::vector<std::pair<A,B>> v{{a1, b1}, {a2, b2}, {a3, b3}};
MyBimap map(v.begin(), v.end());
It also didn't work. The documentation isn't exactly clear what kind of iterators this constructor expects, but apparently it's not simply an iterator of std::pair<A, B> objects. Then what does this constructor expect for this kind of bimap?
I use the following "factory function" that takes a braced initializer list and returns a boost::bimap:
template <typename L, typename R>
boost::bimap<L, R>
make_bimap(std::initializer_list<typename boost::bimap<L, R>::value_type> list)
{
return boost::bimap<L, R>(list.begin(), list.end());
}
Usage:
auto my_bimap = make_bimap<int, int>({{1, 2}, {3, 4}, {5, 6}});
C++ beginner here: You can use boost::assign to generate the initialization. I found this solution here.
Example:
#include <boost/bimap.hpp>
#include <boost/assign.hpp>
//declare the type of bimap we want
typedef boost::bimap<int, std::string> bimapType;
//init our bimap
bimapType bimap = boost::assign::list_of< bimapType::relation >
( 1, "one" )
( 2, "two" )
( 3, "three" );
//test if everything works
int main(int argc, char **argv)
{
std::cout << bimap.left.find(1)->second << std::endl;
std::cout << bimap.left.find(2)->second << std::endl;
std::cout << bimap.left.find(3)->second << std::endl;
std::cout << bimap.right.find("one")->second << std::endl;
std::cout << bimap.right.find("two")->second << std::endl;
std::cout << bimap.right.find("three")->second << std::endl;
/* Output:
* one
* two
* three
* 1
* 2
* 3
*/
}
The iterator begin/end should be for a sequence of bimap values.
boost::bimap< A, B>::value_type
A bimap value is a lot like a std::pair and can be initialized with {a1, b1}syntax. A vector of them seems to work too, which provides usable iterators for the constructor.
Ok, here is an example that compiles and runs for me (gcc 4.8.2 --std=c++11)
#include <vector>
#include <boost/bimap.hpp>
using namespace std;
int main() {
typedef boost::bimap< int, int > MyBimap;
std::vector<MyBimap::value_type > v{{1, 2}, {3, 4}, {5, 6}};
MyBimap M(v.begin(),v.end());
std::cout << "The size is " << M.size()
<< std::endl;
std::cout << "An entry is 1:" << M.left.at(1)
<< std::endl;
}
This leaves a vector to be cleaned up, which might in some cases be an issue. Here a short helper class that might solve your problem as well. As the class instance is a temporary, it gets cleaned up immediately wherever it is used. This is based on https://stackoverflow.com/a/1730798/3103767
// helper for bimap init (simple, lightweight version of boost::assign)
template <typename T, typename U>
class create_bimap
{
typedef boost::bimap< T, U > bimap_type;
typedef typename bimap_type::value_type value_type;
private:
boost::bimap<T, U> m_map;
public:
create_bimap(const T& left, const U& right)
{
m_map.insert( value_type(left, right) );
}
create_bimap<T, U>& operator()(const T& left, const U& right)
{
m_map.insert( value_type(left, right) );
return *this;
}
operator boost::bimap<T, U>()
{
return m_map;
}
};
Use as follows:
boost::bimap<string,int> myMap = create_bimap<string,int>
("c",1)
("b",2)
("a",3);
I have an integer array as shown:
int ia[] = {1, 2, 3, 4, 5, 6};
I want to convert it to a list<int> and a vector<int>. The obvious way that comes to my mind is iterating over the array, and add the elements to the list<int> and vector<int>:
for (auto val: ia) {
ilist.push_back(val);
ivec.push_vack(val);
}
I just wanted to know, whether there is any other way, probably any available library function?
You can use a two-iterator constructor:
std::list<int> ilist(std::begin(ia), std::end(ia));
std::vector<int> ivec(std::begin(ia), std::end(ia));
If you don't have C++11 support for std::begin and std::end, you can use
std::list<int> ilist(ia, ia + 6);
where in real code you would aim to provide an array length function instead of using 6 explicitly.
Better still, you could role out your own begin and end function templates, for example
template< class T, std::size_t N >
T* my_end( const T (&a)[N] )
{
return &a[N];
}
Edit here's an array length function template:
template< class T, size_t N >
std::size_t size( const T (&)[N] )
{
return N;
}
Let's assume that I have a function that prints a set of numbers: 1, 2, 3, 4, 5 and these numbers can either be stored as an array, or, as a vector. In my current system I therefore have two functions that accept either of these parameters.
void printNumbers(std::vector<double> &printNumbers)
{
//code
//....
}
And therefore one that accepts an array..
void printNumbers(int* numbers)
{
//code
//...
}
This seems a waste of code, and, I was thinking that I could better take advantage of code re-use which got me thinking to this: Can I use a template to determine which type of input is being passed to the function? For example, whether it's a vector or an array or just a single integer value?
Here is the prototype below:
#include <iostream>
using namespace std;
template<class T>
void printNumbers(T numbers)
{
// code
// code
}
int main(int argc, char *argv[]) {
int numbers[] = {1, 2, 3, 4, 5};
printNumbers<array> (numbers);
}
Any help would be greatly appreciated.
The usual idiom is to pass iterators, one for the first element of the range, and one corresponding to "one past the end":
template<class Iterator>
void printNumbers(Iterator begin, Iterator end)
{
for (Iterator i = begin; i != end; ++i)
std::cout << *i << " ";
std::cout << "\n";
}
int main()
{
int numbers[] = {1, 2, 3, 4, 5};
printNumbers(numbers, numbers + 5);
printNumbers(std::begin(numbers), std::end(numbers); // C++11 version
std::vector<int> v{1,2,3,4,5};
printNumbers(v.begin(), v.end());
}
You could follow the example of the STL algorithms and accept an iterator range. Containers have their iterator types, and pointers can be used to iterate over arrays:
template <typename InputIterator>
void printNumbers(InputIterator start, InputIterator end) {
// print "*start", and iterate up to "end"
}
For convenience, you can overload this to accept containers and arrays directly:
template <typename Container>
void printNumbers(Container const & c) {
printNumbers(c.begin(), c.end());
}
template <typename T, size_t N>
void printNumbers(T (const & a)[N]) {
printNumbers(a, a+N);
}
In C++11 (or with your own begin and end functions) you can combine these:
template <typename Container>
void printNumbers(Container const & c) {
printNumbers(std::begin(c), std::end(c));
}