Why the Range-based for loop does not work with pointer of arrays?
auto pCollection = new int[3] { 0,1,2 };
// error C3312: no callable 'begin' function found for type 'int *'
for (auto value : pCollection)
{
std::cout << value << std::endl;
}
delete[] pCollection;
but can be used on arrays:
int collection[3]{ 0,1,2 };
for (auto value : collection)
{
std::cout << value << std::endl;
}
A pointer is not an array. There is no way to know, from the pointer alone, how many elements there may or may not be at the location that a pointer points to.
Suppose your dynamically-allocated array is returned from a function:
int *pCollection = getCollection();
How will you find the end of the array? Well, you can't -- that pointer only points to the first element, it does not bundle any size information. In fact, it could point to a single int allocated with new and you wouldn't know either. Pointers just aren't containers -- only pointers.
auto pCollection = new int[3] { 0,1,2 };
this isn't an int[3]. It is an int* that points to a buffer of 3 int.
The type carries no information about its size.
int collection[3]{ 0,1,2 };
this is an int[3]. Its type says how big it is.
Here we create two different sized new'd arrays
auto pCollection = (rand()%2)?new int[3] { 0,1,2 }:new int[5]{1,2,3,4,5};
and store a pointer to one or the other. The type of pCollection doesn't know how big it is. There is no way in C++ to get at its size, and as destruction is trivial, it would be acceptable for the OS to give us enough room for 8 ints and say "whatever" about the extra space. So even accessing low level memory APIs may not tell us how large it is.
Witn an actual int[3],
for (auto value : collection) {
std::cout << value << std::endl;
}
this statement can use the type of collection to know how many elements to visit. std::begin and std::end are overloaded to do the right thing, and for(:) loops are similarly specified to do the right thing.
With an int*, there is no type information about its length stored.
We can store it ourselves. And provide a type that knows it.
Here is a quick one:
template<class It, class R=void>
struct range_t {
It b, e;
It begin() const { return b; }
It end() const { return e; }
range_t(It s, It f):b(std::move(s)), e(std::move(f)) {}
range_t() noexcept(noexcept(It{})) :range_t({},{}) {}
range_t(range_t const&)=default;
range_t(range_t &&)=default;
range_t& operator=(range_t const&)=default;
range_t& operator=(range_t &&)=default;
~range_t()=default;
decltype(auto) front() const { return *begin(); }
decltype(auto) back() const { return *std::prev(end()); }
using own_type = std::conditional_t<
std::is_same<R,void>::value,
range_t,
R
>;
own_type without_front( std::size_t N=1 ) const {
return {std::next(begin(), N), end()};
}
own_type without_back( std::size_t N=1 ) const {
return {begin(), std::prev(end(),N)};
}
std::size_t size() const {
return std::distance( begin(), end() );
}
bool empty() const {
return begin()==end();
}
};
template<class T>
struct span_t:range_t<T*, span_t<T>> {
span_t(T* s, T* f):range_t<T*>(s, f) {}
span_t(T* s, std::size_t l):span_t(s, s+l) {}
T& operator[](std::size_t n)const{ return begin()[n]; }
span_t( range_t<T*> o ):range_t<T*>(o) {}
span_t( span_t const& ) = default;
span_t& operator=( span_t const& ) = default;
span_t() noexcept(true) : span_t(nullptr, nullptr) {}
};
template<class T>
span_t<T> span(T* s, T* f){ return {s,f}; }
template<class T>
span_t<T> span(T* s, std::size_t length){ return {s,length}; }
so now we can do this:
auto pCollection = new int[3] { 0,1,2 };
for (auto value : span(pCollection,3)) {
std::cout << value << std::endl;
}
delete[] pCollection;
and bob is your uncle.
Note GSL has a better more complete span<T> type.
To turn it into range use
boost::make_iterator_range(pCollection, pCollection+3)
Related
I have a vector of vectors of strings. I want to find the lengths of the longest string in each column. All the subvectors are of the same length and have an element stored in it, so it would be rather easy to find it with two for loops and reversed indices.
vector<vector<string>> myvec = {
{ "a", "aaa", "aa"},
{"bb", "b", "bbbb"},
{"cc", "cc", "ccc"}
};
But is it possible to do it with iterators without using indices?
Assuming the inner vectors are all the same length, you can have something like
template <typename T>
class columnwise {
std::vector<std::vector<T>> * underlying;
struct proxy {
std::vector<std::vector<T>> * underlying;
std::vector<T>::difference_type offset;
struct iterator {
std::vector<std::vector<T>>::iterator outer;
std::vector<T>::difference_type offset;
using reference = typename std::vector<T>::reference;
using pointer = typename std::vector<T>::pointer;
iterator operator++() { ++outer; return *this; }
reference operator*() { return *(outer->begin() + offset); }
pointer operator->() { return (outer->begin() + offset).operator->(); }
bool operator==(iterator rhs) { return (outer == rhs.outer) && (offset == rhs.offset); }
};
public:
iterator begin() { return { underlying->begin(), offset }; }
iterator end() { return { underlying->end(), offset }; }
};
struct iterator {
// member type aliases
std::vector<std::vector<T>> * underlying;
std::vector<T>::difference_type offset;
iterator operator++() { ++offset; return *this; }
proxy operator*() { return { underlying, offset }; }
bool operator==(iterator rhs) { return (underlying== rhs.underlying) && (offset == rhs.offset); }
};
std::vector<T>::difference_type inner_size() { if (auto it = underlying->begin(); it != underlying->end()) { return it->size(); } return 0; }
public:
columnwise(std::vector<std::vector<T>> & vec) : underlying(&vec) {}
iterator begin() { return { underlying, 0 }; }
iterator end() { return { underlying, inner_size() }; }
};
Which iterates as you expect.
What about something like this?
std::vector<std::size_t> max_lengths(myvec.front().size(), 0);
for (auto const& strings : myvec) {
std::transform(max_lengths.begin(), max_lengths.end(), strings.begin(), max_lengths.begin(),
[](std::size_t l, std::string const& s) {
return std::max(l, s.size());
}
);
}
Demo
Here is a solution using C++20 ranges and lambdas that is similar to Nelfeals answer:
// returns a function returning the i-th element of an iterable container
auto ith_element = [](size_t i) {
return [i](auto const& v){
return v[i];
};
};
// returns a range over the i-th column
auto column = [ith_element](size_t i) {
return std::views::transform(ith_element(i)); // returns a range containing only the i-th elements of the elements in the input range
};
// returns the size of something
auto length = [](auto const& s){ return s.size(); };
// returns the max length of the i-th column
auto max_length_of_col = [column, length](auto const& v, size_t i) {
return std::ranges::max(
v | column(i) | std::views::transform(length)
);
};
I personally like how the ranges library helps you convey intent with your code, rather than having to prescribe the procedure to achieve your goal.
Note that if you replace the body of inner lambda in ith_element with the following block, it will also work for iterable containers without random access.
auto it = v.cbegin();
std::ranges::advance(it, i);
return *it
Demo
As a final remark, this solution lets you iterate over one column given an index of the column. I would advise against implementing a column iterator for vector<vector>: The existence of an iterator implies that something exists in memory that you can iterate over. The existence of columns is only implied by the additional information that you have given us, namely that all rows have the same length. If you do want iterators both for columns and rows, I would wrap your container in a new type (usually called matrix or similar) that properly conveys that intent. Then you can implement iterators for that new type, see Calath's answer.
EDIT:
I realized that my argument against a column iterator can be used as an argument against the column function in this answer as well. So here is a solution that let's you iterate over columns in a range-based for loop intead of iterating over column indices:
for (auto column : columns(myvec)){
std::cout << max_length(column) << std::endl;
}
I have objects that I need to hash with SHA256. The object has several fields as follows:
class Foo {
// some methods
protected:
std::array<32,int> x;
char y[32];
long z;
}
Is there a way I can directly access the bytes representing the 3 member variables in memory as I would a struct ? These hashes need to be computed as quickly as possible so I want to avoid malloc'ing a new set of bytes and copying to a heap allocated array. Or is the answer to simply embed a struct within the class?
It is critical that I get the exact binary representation of these variables so that the SHA256 comes out exactly the same given that the 3 variables are equal (so I can't have any extra padding bytes etc included going into the hash function)
Most Hash classes are able to take multiple regions before returning the hash, e.g. as in:
class Hash {
public:
void update(const void *data, size_t size) = 0;
std::vector<uint8_t> digest() = 0;
}
So your hash method could look like this:
std::vector<uint8_t> Foo::hash(Hash *hash) const {
hash->update(&x, sizeof(x));
hash->update(&y, sizeof(y));
hash->update(&z, sizeof(z));
return hash->digest();
}
You can solve this by making an iterator that knows the layout of your member variables. Make Foo::begin() and Foo::end() functions and you can even take advantage of range-based for loops.
If you can increment it and dereference it, you can use it any other place you're able to use a LegacyForwardIterator.
Add in comparison functions to get access to the common it = X.begin(); it != X.end(); ++it idiom.
Some downsides include: ugly library code, poor maintainability, and (in this current form) no regard for endianess.
The solution to the latter downside is left as an exercise to the reader.
#include <array>
#include <iostream>
class Foo {
friend class FooByteIter;
public:
FooByteIter begin() const;
FooByteIter end() const;
Foo(const std::array<int, 2>& x, const char (&y)[2], long z)
: x_{x}
, y_{y[0], y[1]}
, z_{z}
{}
protected:
std::array<int, 2> x_;
char y_[2];
long z_;
};
class FooByteIter {
public:
FooByteIter(const Foo& foo)
: ptr_{reinterpret_cast<const char*>(&(foo.x_))}
, x_end_{reinterpret_cast<const char*>(&(foo.x_)) + sizeof(foo.x_)}
, y_begin_{reinterpret_cast<const char*>(&(foo.y_))}
, y_end_{reinterpret_cast<const char*>(&(foo.y_)) + sizeof(foo.y_)}
, z_begin_{reinterpret_cast<const char*>(&(foo.z_))}
{}
static FooByteIter end(const Foo& foo) {
FooByteIter fbi{foo};
fbi.ptr_ = reinterpret_cast<const char*>(&foo.z_) + sizeof(foo.z_);
return fbi;
}
bool operator==(const FooByteIter& other) const { return ptr_ == other.ptr_; }
bool operator!=(const FooByteIter& other) const { return ! (*this == other); }
FooByteIter& operator++() {
ptr_++;
if (ptr_ == x_end_) {
ptr_ = y_begin_;
}
else if (ptr_ == y_end_) {
ptr_ = z_begin_;
}
return *this;
}
FooByteIter operator++(int) {
FooByteIter pre = *this;
(*this)++;
return pre;
}
char operator*() const {
return *ptr_;
}
private:
const char* ptr_;
const char* const x_end_;
const char* const y_begin_;
const char* const y_end_;
const char* const z_begin_;
};
FooByteIter Foo::begin() const {
return FooByteIter(*this);
}
FooByteIter Foo::end() const {
return FooByteIter::end(*this);
}
template <typename InputIt>
char checksum(InputIt first, InputIt last) {
char check = 0;
while (first != last) {
check += (*first);
++first;
}
return check;
}
int main() {
Foo f{{1, 2}, {3, 4}, 5};
for (const auto b : f) {
std::cout << (int)b << ' ';
}
std::cout << std::endl;
std::cout << "Checksum is: " << (int)checksum(f.begin(), f.end()) << std::endl;
}
You can generalize this further by making serialization functions for all data types you might care about, allowing serialization of classes that aren't plain-old-data types.
Warning
This code assumes that the underlying types being serialized have no internal padding, themselves. This answer works for this datatype because it is made of types which themselves do not pad. To make this work for datatypes that have datatypes that have padding, this method would need to be recursed all the way down.
Just cast a pointer to object to a pointer to char. You can iterate through the bytes by increment. Use sizeof(foo) to check overflow.
As long as you're able to make your class an aggregate, i.e. std::is_aggregate_v<T> == true, you can actually sort-of reflect the members of the structure.
This allows you to easily hash the members without actually having to name them. (also you don't have to remember updating your hash function every time you add a new member)
Step 1: Getting the number of members inside the aggregate
First we need to know how many members a given aggregate type has.
We can check this by (ab-)using aggregate initialization.
Example:
Given struct Foo { int i; int j; };:
Foo a{}; // ok
Foo b{{}}; // ok
Foo c{{}, {}}; // ok
Foo d{{}, {}, {}}; // error: too many initializers for 'Foo'
We can use this to get the number of members inside the struct, by trying to add more initializers until we get an error:
template<class T>
concept aggregate = std::is_aggregate_v<T>;
struct any_type {
template<class T>
operator T() {}
};
template<aggregate T>
consteval std::size_t count_members(auto ...members) {
if constexpr (requires { T{ {members}... }; } == false)
return sizeof...(members) - 1;
else
return count_members<T>(members..., any_type{});
}
Notice that i used {members}... instead of members....
This is because of arrays - a structure like struct Bar{int i[2];}; could be initialized with 2 elements, e.g. Bar b{1, 2}, so our function would have returned 2 for Bar if we had used members....
Step 2: Extracting the members
Now that we know how many members our structure has, we can use structured bindings to extract them.
Unfortunately there is no way in the current standard to create a structured binding expression with a variable amount of expressions, so we have to add a few extra lines of code for each additional member we want to support.
For this example i've only added a max of 4 members, but you can add as many as you like / need:
template<aggregate T>
constexpr auto tie_struct(T const& data) {
constexpr std::size_t fieldCount = count_members<T>();
if constexpr(fieldCount == 0) {
return std::tie();
} else if constexpr (fieldCount == 1) {
auto const& [m1] = data;
return std::tie(m1);
} else if constexpr (fieldCount == 2) {
auto const& [m1, m2] = data;
return std::tie(m1, m2);
} else if constexpr (fieldCount == 3) {
auto const& [m1, m2, m3] = data;
return std::tie(m1, m2, m3);
} else if constexpr (fieldCount == 4) {
auto const& [m1, m2, m3, m4] = data;
return std::tie(m1, m2, m3, m4);
} else {
static_assert(fieldCount!=fieldCount, "Too many fields for tie_struct! add more if statements!");
}
}
The fieldCount!=fieldCount in the static_assert is intentional, this prevents the compiler from evaluating it prematurely (it only complains if the else case is actually hit)
Now we have a function that can give us references to each member of an arbitrary aggregate.
Example:
struct Foo {int i; float j; std::string s; };
Foo f{1, 2, "miau"};
// tup is of type std::tuple<int const&, float const&, std::string const&>
auto tup = tie_struct(f);
// this will output "12miau"
std::cout << std::get<0>(tup) << std::get<1>(tup) << std::get<2>(tup) << std::endl;
Step 3: hashing the members
Now that we can convert any aggregate into a tuple of its members, hashing it shouldn't be a big problem.
You can basically hash the individual types like you want and then combine the individual hashes:
// for merging two hash values
std::size_t hash_combine(std::size_t h1, std::size_t h2)
{
return (h2 + 0x9e3779b9 + (h1<<6) + (h1>>2)) ^ h1;
}
// Handling primitives
template <class T, class = void>
struct is_std_hashable : std::false_type { };
template <class T>
struct is_std_hashable<T, std::void_t<decltype(std::declval<std::hash<T>>()(std::declval<T>()))>> : std::true_type { };
template <class T>
concept std_hashable = is_std_hashable<T>::value;
template<std_hashable T>
std::size_t hash(T value) {
return std::hash<T>{}(value);
}
// Handling tuples
template<class... Members>
std::size_t hash(std::tuple<Members...> const& tuple) {
return std::apply([](auto const&... members) {
std::size_t result = 0;
((result = hash_combine(result, hash(members))), ...);
return result;
}, tuple);
}
template<class T, std::size_t I>
using Arr = T[I];
// Handling arrays
template<class T, std::size_t I>
std::size_t hash(Arr<T, I> const& arr) {
std::size_t result = 0;
for(T const& elem : arr) {
std::size_t h = hash(elem);
result = hash_combine(result, h);
}
return result;
};
// Handling structs
template<aggregate T>
std::size_t hash(T const& agg) {
return hash(tie_struct(agg));
}
This allows you to hash basically any aggregate struct, even with arrays and nested structs:
struct Foo{ int i; double d; std::string s; };
struct Bar { Foo k[10]; float f; };
std::cout << hash(Foo{1, 1.2f, "miau"}) << std::endl;
std::cout << hash(Bar{}) << std::endl;
full example on godbolt
Footnotes
This only works with aggregates
No need to worry about padding because we access the members directly.
You have to add a few more ifs into tie_struct if you need more than 4 members
The provided hash() function doesn't handle all types - if you need e.g. std::array, std::pair, etc... you need to add overloads for those.
It's a lot of boilerplate code, but it's insanely powerful.
You can also use Boost.PFR for the aggregate-to-tuple part, if you are allowed to use boost
Short version
Can I reinterpret_cast a std::vector<void*>* to a std::vector<double*>*?
What about with other STL containers?
Long version
I have a function to recast a vector of void pointers to a datatype specified by a template argument:
template <typename T>
std::vector<T*> recastPtrs(std::vector<void*> const& x) {
std::vector<T*> y(x.size());
std::transform(x.begin(), x.end(), y.begin(),
[](void *a) { return static_cast<T*>(a); } );
return y;
}
But I was thinking that copying the vector contents isn't really necessary, since we're really just reinterpreting what's being pointed to.
After some tinkering, I came up with this:
template <typename T>
std::vector<T*> recastPtrs(std::vector<void*>&& x) {
auto xPtr = reinterpret_cast<std::vector<T*>*>(&x);
return std::vector<T*>(std::move(*xPtr));
}
So my questions are:
Is it safe to reinterpret_cast an entire vector like this?
What if it was a different kind of container (like a std::list or std::map)? To be clear, I mean casting a std::list<void*> to std::list<T*>, not casting between STL container types.
I'm still trying to wrap my head around move semantics. Am I doing it right?
And one follow-up question: What would be the best way to generate a const version without code duplication? i.e. to define
std::vector<T const*> recastPtrs(std::vector<void const*> const&);
std::vector<T const*> recastPtrs(std::vector<void const*>&&);
MWE
#include <vector>
#include <algorithm>
#include <iostream>
template <typename T>
std::vector<T*> recastPtrs(std::vector<void*> const& x) {
std::vector<T*> y(x.size());
std::transform(x.begin(), x.end(), y.begin(),
[](void *a) { return static_cast<T*>(a); } );
return y;
}
template <typename T>
std::vector<T*> recastPtrs(std::vector<void*>&& x) {
auto xPtr = reinterpret_cast<std::vector<T*>*>(&x);
return std::vector<T*>(std::move(*xPtr));
}
template <typename T>
void printVectorAddr(std::vector<T> const& vec) {
std::cout<<" vector object at "<<&vec<<", data()="<<vec.data()<<std::endl;
}
int main(void) {
std::cout<<"Original void pointers"<<std::endl;
std::vector<void*> voidPtrs(100);
printVectorAddr(voidPtrs);
std::cout<<"Elementwise static_cast"<<std::endl;
auto dblPtrs = recastPtrs<double>(voidPtrs);
printVectorAddr(dblPtrs);
std::cout<<"reintepret_cast entire vector, then move ctor"<<std::endl;
auto dblPtrs2 = recastPtrs<double>(std::move(voidPtrs));
printVectorAddr(dblPtrs2);
}
Example output:
Original void pointers
vector object at 0x7ffe230b1cb0, data()=0x21de030
Elementwise static_cast
vector object at 0x7ffe230b1cd0, data()=0x21de360
reintepret_cast entire vector, then move ctor
vector object at 0x7ffe230b1cf0, data()=0x21de030
Note that the reinterpret_cast version reuses the underlying data structure.
Previously-asked questions that didn't seem relevant
These are the questions that come up when I tried to search this:
reinterpret_cast vector of class A to vector of class B
reinterpret_cast vector of derived class to vector of base class
reinterpret_cast-ing vector of one type to a vector of another type which is of the same type
And the answer to these was a unanimous NO, with reference to the strict aliasing rule. But I figure that doesn't apply to my case, since the vector being recast is an rvalue, so there's no opportunity for aliasing.
Why I'm trying to do this
I'm interfacing with a MATLAB library that gives me data pointers as void* along with a variable indicating the datatype. I have one function that validates the inputs and collects these pointers into a vector:
void parseInputs(int argc, mxArray* inputs[], std::vector<void*> &dataPtrs, mxClassID &numericType);
I can't templatize this part since the type is not known until runtime. On the other side, I have numeric routines to operate on vectors of a known datatype:
template <typename T>
void processData(std::vector<T*> const& dataPtrs);
So I'm just trying to connect one to the other:
void processData(std::vector<void*>&& voidPtrs, mxClassID numericType) {
switch (numericType) {
case mxDOUBLE_CLASS:
processData(recastPtrs<double>(std::move(voidPtrs)));
break;
case mxSINGLE_CLASS:
processData(recastPtrs<float>(std::move(voidPtrs)));
break;
default:
assert(0 && "Unsupported datatype");
break;
}
}
Given the comment that you're receiving the void * from a C library (something like malloc), it seems like we can probably narrow the problem down quite a bit.
In particular, I'd guess you're really dealing with something that's more like an array_view than a vector. That is, you want something that lets you access some data cleanly. You might change individual items in that collection, but you'll never change the collection as a whole (e.g., you won't try to do a push_back that could need to expand the memory allocation).
For such a case, you can pretty easily create a wrapper of your own that gives you vector-like access to the data--defines an iterator type, has a begin() and end() (and if you want, the others like rbegin()/rend(), cbegin()/cend() and crbegin()/crend()), as well as an at() that does range-checked indexing, and so on.
So a fairly minimal version could look something like this:
#pragma once
#include <cstddef>
#include <stdexcept>
#include <cstdlib>
#include <iterator>
template <class T> // note: no allocator, since we don't do allocation
class array_view {
T *data;
std::size_t size_;
public:
array_view(void *data, std::size_t size_) : data(reinterpret_cast<T *>(data)), size_(size_) {}
T &operator[](std::size_t index) { return data[index]; }
T &at(std::size_t index) {
if (index > size_) throw std::out_of_range("Index out of range");
return data[index];
}
std::size_t size() const { return size_; }
typedef T *iterator;
typedef T const &const_iterator;
typedef T value_type;
typedef T &reference;
iterator begin() { return data; }
iterator end() { return data + size_; }
const_iterator cbegin() { return data; }
const_iterator cend() { return data + size_; }
class reverse_iterator {
T *it;
public:
reverse_iterator(T *it) : it(it) {}
using iterator_category = std::random_access_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = T;
using pointer = T *;
using reference = T &;
reverse_iterator &operator++() {
--it;
return *this;
}
reverse_iterator &operator--() {
++it;
return *this;
}
reverse_iterator operator+(size_t size) const {
return reverse_iterator(it - size);
}
reverse_iterator operator-(size_t size) const {
return reverse_iterator(it + size);
}
difference_type operator-(reverse_iterator const &r) const {
return it - r.it;
}
bool operator==(reverse_iterator const &r) const { return it == r.it; }
bool operator!=(reverse_iterator const &r) const { return it != r.it; }
bool operator<(reverse_iterator const &r) const { return std::less<T*>(r.it, it); }
bool operator>(reverse_iterator const &r) const { return std::less<T*>(it, r.it); }
T &operator *() { return *(it-1); }
};
reverse_iterator rbegin() { return data + size_; }
reverse_iterator rend() { return data; }
};
I've tried to show enough that it should be fairly apparent how to add most of the missing functionality (e.g., crbegin()/crend()), but I haven't worked really hard at including everything here, since much of what's left is more repetitive and tedious than educational.
This is enough to use the array_view in most of the typical vector-like ways. For example:
#include "array_view"
#include <iostream>
#include <iterator>
int main() {
void *raw = malloc(16 * sizeof(int));
array_view<int> data(raw, 16);
std::cout << "Range based:\n";
for (auto & i : data)
i = rand();
for (auto const &i : data)
std::cout << i << '\n';
std::cout << "\niterator-based, reverse:\n";
auto end = data.rend();
for (auto d = data.rbegin(); d != end; ++d)
std::cout << *d << '\n';
std::cout << "Forward, counted:\n";
for (int i=0; i<data.size(); i++) {
data[i] += 10;
std::cout << data[i] << '\n';
}
}
Note that this doesn't attempt to deal with copy/move construction at all, nor with destruction. At least as I've formulated it, the array_view is a non-owning view into some existing data. It's up to you (or at least something outside of the array_view) to destroy the data when appropriate. Since we're not destroying the data, we can use the compiler-generated copy and move constructors without any problem. We won't get a double-delete from doing a shallow copy of the pointer, because we don't do any delete when the array_view is destroyed.
No, you cannot do anything like this in Standard C++.
The strict aliasing rule says that to access an object of type T, you must use an expression of type T; with a very short list of exceptions to that.
Accessing a double * via a void * expression is not such an exception; let alone a vector of each. Nor is it an exception if you accessed the object of type T via an rvalue.
Background
I'm working with an embedded platform with the following restrictions:
No heap
No Boost libraries
C++11 is supported
I've dealt with the following problem a few times in the past:
Create an array of class type T, where T has no default constructor
The project only recently added C++11 support, and up until now I've been using ad-hoc solutions every time I had to deal with this. Now that C++11 is available, I thought I'd try to make a more general solution.
Solution Attempt
I copied an example of std::aligned_storage to come up with the framework for my array type. The result looks like this:
#include <type_traits>
template<class T, size_t N>
class Array {
// Provide aligned storage for N objects of type T
typename std::aligned_storage<sizeof(T), alignof(T)>::type data[N];
public:
// Build N objects of type T in the aligned storage using default CTORs
Array()
{
for(auto index = 0; index < N; ++index)
new(data + index) T();
}
const T& operator[](size_t pos) const
{
return *reinterpret_cast<const T*>(data + pos);
}
// Other methods consistent with std::array API go here
};
This is a basic type - Array<T,N> only compiles if T is default-constructible. I'm not very familiar with template parameter packing, but looking at some examples led me to the following:
template<typename ...Args>
Array(Args&&... args)
{
for(auto index = 0; index < N; ++index)
new(data + index) T(args...);
}
This was definitely a step in the right direction. Array<T,N> now compiles if passed arguments matching a constructor of T.
My only remaining problem is constructing an Array<T,N> where different elements in the array have different constructor arguments. I figured I could split this into two cases:
1 - User Specifies Arguments
Here's my stab at the CTOR:
template<typename U>
Array(std::initializer_list<U> initializers)
{
// Need to handle mismatch in size between arg and array
size_t index = 0;
for(auto arg : initializers) {
new(data + index) T(arg);
index++;
}
}
This seems to work fine, aside from needing to handle a dimension mismatch between the array and initializer list, but there are a number of ways to deal with that that aren't important. Here's an example:
struct Foo {
explicit Foo(int i) {}
};
void bar() {
// foos[0] == Foo(0)
// foos[1] == Foo(1)
// ..etc
Array<Foo,10> foos {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
}
2 - Arguments Follow Pattern
In my previous example, foos is initialized with an incrementing list, similar to std::iota. Ideally I'd like to support something like the following, where range(int) returns SOMETHING that can initialize the array.
// One of these should initialize foos with parameters returned by range(10)
Array<Foo,10> foosA = range(10);
Array<Foo,10> foosB {range(10)};
Array<Foo,10> foosC = {range(10)};
Array<Foo,10> foosD(range(10));
Googling has shown me that std::initializer_list isn't a "normal" container, so I don't think there's any way for me to make range(int) return a std::initializer_list depending on the function parameter.
Again, there are a few options here:
Parameters specified at run-time (function return?)
Parameters specified at compile-time (constexpr function return? templates?)
Questions
Are there any issues with this solution so far?
Does anyone have a suggestion to generate constructor parameters? I can't think of a solution at runtime or compile-time other than hard-coding an std::initializer_list, so any ideas are welcome.
If i understand your problem correctly, I've also stumbled across std::array's total inflexibility regarding element construction in favor of aggregate initialization (and an absense of statically-allocated container with flexible element contruction options). The best approach I came up with was creating a custom array-like container which accepts an iterator to construct it's elements.
This is totally flexible solution:
Works for both fixed-size and dynamic-sized containers
Can pass different or same parameters to element constructors
Can call constructors with one or multiple (tuple piecewise construction) arguments, or even different constructors for different elements (with inversion of control)
For your example it would be like:
const size_t SIZE = 10;
std::array<int, SIZE> params;
for (size_t c = 0; c < SIZE; c++) {
params[c] = c;
}
Array<Foo, SIZE> foos(iterator_construct, ¶ms[0]); //iterator_construct is a special tag to call specific constructor
// also, we are able to pass a pointer as iterator, since it has both increment and dereference operators
Note: you can totally skip parameters array allocation here by using custom iterator class, which calculates it's value from it's position on-the-fly.
For multiple-argument constructor that would be:
const size_t SIZE = 10;
std::array<std::tuple<int, float>, SIZE> params; // will call Foo(int, float)
for (size_t c = 0; c < SIZE; c++) {
params[c] = std::make_tuple(c, 1.0f);
}
Array<Foo, SIZE> foos(iterator_construct, piecewise_construct, ¶ms[0]);
Concrete implementation example is kinda big piece of code, so please let me know if you want more insights into implementation details besides the general idea - I will update my answer then.
I'd use a factory lambda.
The lambda takes a pointer to where to construct and an index, and is responsible for constructing.
This makes copy/move easy to write as well, which is a good sign.
template<class T, std::size_t N>
struct my_array {
T* data() { return (T*)&buffer; }
T const* data() const { return (T const*)&buffer; }
// basic random-access container operations:
T* begin() { return data(); }
T const* begin() const { return data(); }
T* end() { return data()+N; }
T const* end() const { return data()+N; }
T& operator[](std::size_t i){ return *(begin()+i); }
T const& operator[](std::size_t i)const{ return *(begin()+i); }
// useful utility:
bool empty() const { return N!=0; }
T& front() { return *begin(); }
T const& front() const { return *begin(); }
T& back() { return *(end()-1); }
T const& back() const { return *(end()-1); }
std::size_t size() const { return N; }
// construct from function object:
template<class Factory,
typename std::enable_if<!std::is_same<std::decay_t<Factory>, my_array>::value, int> =0
>
my_array( Factory&& factory ) {
std::size_t i = 0;
try {
for(; i < N; ++i) {
factory( (void*)(data()+i), i );
}
} catch(...) {
// throw during construction. Unroll creation, and rethrow:
for(std::size_t j = 0; j < i; ++j) {
(data()+i-j-1)->~T();
}
throw;
}
}
// other constructors, in terms of above naturally:
my_array():
my_array( [](void* ptr, std::size_t) {
new(ptr) T();
} )
{}
my_array(my_array&& o):
my_array( [&](void* ptr, std::size_t i) {
new(ptr) T( std::move(o[i]) );
} )
{}
my_array(my_array const& o):
my_array( [&](void* ptr, std::size_t i) {
new(ptr) T( o[i] );
} )
{}
my_array& operator=(my_array&& o) {
for (std::size_t i = 0; i < N; ++i)
(*this)[i] = std::move(o[i]);
return *this;
}
my_array& operator=(my_array const& o) {
for (std::size_t i = 0; i < N; ++i)
(*this)[i] = o[i];
return *this;
}
private:
using storage = typename std::aligned_storage< sizeof(T)*N, alignof(T) >::type;
storage buffer;
};
it defines my_array(), but that is only compiled if you try to compile it.
Supporting initializer list is relatively easy. Deciding what to do when the il isn't long enough, or too long, is hard. I think you might want:
template<class Fail>
my_array( std::initializer_list<T> il, Fail&& fail ):
my_array( [&](void* ptr, std::size_t i) {
if (i < il.size()) new(ptr) T(il[i]);
else fail(ptr, i);
} )
{}
which requires you pass in a "what to do on fail". We could default to throw by adding:
template<class WhatToThrow>
struct throw_when_called {
template<class...Args>
void operator()(Args&&...)const {
throw WhatToThrow{"when called"};
}
};
struct list_too_short:std::length_error {
list_too_short():std::length_error("list too short") {}
};
template<class Fail=ThrowWhenCalled<list_too_short>>
my_array( std::initializer_list<T> il, Fail&& fail={} ):
my_array( [&](void* ptr, std::size_t i) {
if (i < il.size()) new(ptr) T(il[i]);
else fail(ptr, i);
} )
{}
which if I wrote it right, makes a too-short initializer list cause a meaningful throw message. On your platform, you could just exit(-1) if you don't have exceptions.
Multi-dimensional initializers can be created by nesting brace-enclosed lists, as in {{1,2,3}, {4,5,6}}. A function accepting this can be written using nested std::initializer_lists.
Are the data elements guaranteed to be contiguous?
Here's an example:
void f(std::initializer_list<std::initializer_list<int>> a)
{
for(auto const & p: a)
for(auto const & q: p)
std::cout << &q << std::endl;
}
int main()
{
f({{1,2,3}, {4,5,6}});
return 0;
}
The above code outputs consecutive addresses on my machine.
0x400c60
0x400c64
0x400c68
0x400c6c
0x400c70
0x400c74
It is guaranteed?
Update
The answer must be no.
void g(std::initializer_list<int> a, std::initializer_list<int> b)
{
f({b,a});
}
int main()
{
g({1,2,3}, {4,5,6});
return 0;
}
The output is:
0x400cdc
0x400ce0
0x400ce4
0x400cd0
0x400cd4
0x400cd8
C++11 ยง [support.initlist] 18.9/1 specifies that for std::initializer_list<T> iterator must be T*, so you are guaranteed that sequential elements in a single initializer_list are contiguous.
In the case of nested lists, e.g., std::initializer_list<std::initializer_list<int>>, there is no requirement that all elements are contiguous. The top-level list's begin() must return a pointer to a contiguous array of std::initializer_list<int>, and each of those lists' begin() must return a pointer to a contiguous array of int. Those second-tier int arrays could be scattered all over memory or stored precisely in total order exactly as you observed. Both ways are compliant.
From here (std::initializer_list) :-
Initializer lists may be implemented as a pair of pointers or pointer
and length.
A possible implementation can be (taken & edited from Mingw 4.8.1 initializer_list header ) :
template<class T>
class initializer_list
{
public:
typedef T value_type;
typedef const T& reference;
typedef const T& const_reference;
typedef size_t size_type;
typedef const T* iterator;
typedef const T* const_iterator;
private:
iterator arr;
size_type arr_len;
// The compiler can call a private constructor.
constexpr initializer_list(const_iterator it, size_type len)
: arr(it), arr_len(len) { }
public:
constexpr initializer_list() noexcept
: arr(0), arr_len(0) { }
// Number of elements.
constexpr size_type
size() const noexcept { return arr_len; }
// First element.
constexpr const_iterator
begin() const noexcept { return arr; }
// One past the last element.
constexpr const_iterator
end() const noexcept { return begin() + size(); }
};
The iterators are not magic, its just playing around with pointers. So the answer is yes, its guaranteed.
In second example of yours, it does show the contiguous memory location, you just flipped a and b