std::array constructor inheritance - c++

I'm trying to get extended variant of std::array for math vectors (and expose same interface as array does without boilerplate code). I know about std::valarray but I want fixed size for proper typing in matrix multiplications. Thus I array fits perfectly. But when I try to inherit constructor it fails.
struct vec2d : std::array<float, 2>
{ using array::array; }; // simplified
struct vec : std::vector<float>
{ using vector::vector; };
std::array<float, 2> x = {1, 2};
vec y = {1, 2};
vec2d z = {1, 2}; // error: could not convert ‘{1, 2}’
// from ‘<brace-enclosed initializer list>’ to ‘vec2d’
This error reported for GCC 4.8.2 and for clang 3.4. Last says that vec2d have only implicit default/copy/move constructors. Yes, array have only implicit ctor in contrary to vector which have ctor from initializer_list. But since ctors are inherited it is natural to inherit possibility to initialize it in a same way as array initialized.
Question: Why we have that error instead of expected behavior (similar to array initialization)?
Note: I that I can write forwarding manually to make it work, but this doesn't look as elegant as ctor inheritance.
struct vec2d : std::array<float, 2>
{
using array::array;
// nasty boilerplate code I don't want to have in C++11
template <typename... Args>
vec2d(Args &&... args) : array({float(std::forward<Args>(args))...}) {}
};

std::array is designed to be an aggregate, so it intentionally does not define any constructors.
Unfortunately, this means it's not possible to inherit from it and get the same behaviour, as aggregates cannot have base classes.
Why do you need to inherit from std::array anyway? Do you plan to add any private members? If not, then you could just build your framework around free functions operating on std::array, or perhaps a typedef to it.
If you really want to inherit from std::array, you'll have to accept losing the aggregate status and provide any constructors you want yourself.
Note that the answer above applies to C++11 and C++14 only. In C++17, the definition of aggregates was loosened to allow public base classes in them, so simply deriving from std::array and removing the using declaration is enought to make the code compile:
struct vec2d : std::array<float, 2>
{ }; // simplified
std::array<float, 2> x = {1, 2};
vec2d z = {1, 2};
[Live example]

I had exactly the same problem, trying to mimic the behavior of numpy.
The way I solved this was to implement a constructor that takes as argument an std::array<float,N> (with & or && or without anything depending on the needs).
The initializer list is then cast automatically to that type, and the right constructor is then called. To be more concrete:
#include <array>
#include <ostream>
#include <iostream>
using namespace std;
template <int N> class Row: public array<double,N>{
public:
Row<N>(){}
// this is the constructor needed
Row<N>(array<double,N> a) : array<double,N> (a) {}
// or, alternatively,
// Row<N>(array<double,N>&& a) : array<double,N> (a) {}
Row<N>(array<double,N>& a) : array<double,N> (a) {}
// other things that may be relevant
Row<N> operator+(Row<N>& other){
Row<N> result;
for(int i =0; i < N ; ++i){
result[i] = (*this)[i] + other[i]; // notice '*'
}
return result;
}
// for lvalues
template <int n> friend ostream& operator<<(ostream& os, Row<n>& r);
// for rvalues
template <int n> friend ostream& operator<<(ostream& os,Row<n>&& r);
};
// for lvalues
template <int N> ostream& operator<<(ostream& os, Row<N>& r){
for(int i =0; i < N ; ++i) os << r[i] << "\t";
return os;
}
// for rvalues
template <int N> ostream& operator<<(ostream& os, Row<N>&& r){
for(int i =0; i < N ; ++i) os << r[i] << "\t";
return os;
}
int main(){
// here Row(array<double,3>&&) is called
// or Row(array<double,3>)
Row<3> a{{1,2,3}}; // same as Row<3> a({1,2,3});
array<double,3> arr = {1,2,3};
Row<3> b(arr);
cout << a << endl; // a and b are lvalues
cout << b << endl;
cout << (a+b) << endl; // (a+b) is a rvalue
return 0;
}

Related

How do I iterate over a group of vectors by their references? [duplicate]

I am trying to iterate over a number of std::lists, sorting each of them. This is the naive approach:
#include<list>
using namespace std;
int main(void){
list<int> a,b,c;
for(auto& l:{a,b,c}) l.sort();
}
producing
aa.cpp:5:25: error: no matching member function for call to 'sort'
for(auto& l:{a,b,c}) l.sort();
~~^~~~
/usr/bin/../lib64/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/bits/stl_list.h:1586:7: note:
candidate function not viable: 'this' argument has type 'const
std::list<int, std::allocator<int> >', but method is not marked const
sort();
^
/usr/bin/../lib64/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/bits/stl_list.h:1596:9: note:
candidate function template not viable: requires 1 argument, but 0 were
provided
sort(_StrictWeakOrdering);
^
1 error generated.
Am I correctly guessing that brace-initializer is creating copy of those lists? And is there a way to not copy them, and make them modifiable inside the loop? (other than making list of pointers to them, which is my current workaround).
You are guessing correctly. std::initializer_list elements are always const (which makes sort()ing them impossible, as sort() is a non-const member function) and its elements are always copied (which would make sort()-ing them meaningless even if they weren't const). From [dcl.init.list], emphasis mine:
An object of type std::initializer_list<E> is constructed from an initializer list as if the implementation
allocated a temporary array of N elements of type const E, where N is the number of elements in the
initializer list. Each element of that array is copy-initialized with the corresponding element of the initializer
list, and the std::initializer_list<E> object is constructed to refer to that array. [ Note: A constructor
or conversion function selected for the copy shall be accessible (Clause 11) in the context of the initializer
list. —end note ] If a narrowing conversion is required to initialize any of the elements, the program is
ill-formed. [ Example:
struct X {
X(std::initializer_list<double> v);
};
X x{ 1,2,3 };
The initialization will be implemented in a way roughly equivalent to this:
const double __a[3] = {double{1}, double{2}, double{3}};
X x(std::initializer_list<double>(__a, __a+3));
assuming that the implementation can construct an initializer_list object with a pair of pointers. —end
example ]
There is no way to make them non-const or non-copied. The pointer solution works:
for (auto l : {&a, &b, &c}) l->sort();
because it's the pointer that's const, not the element it's pointing to. The other alternative would be to write a variadic function template:
template <typename... Lists>
void sortAll(Lists&&... lists) {
// before C++17
using expander = int[];
expander{0, (void(lists.sort()), 0)...};
// C++17 or later
(lists.sort(), ...);
}
sortAll(a, b, c);
You could also, I guess, write a helper to wrap your lists into an array of reference_wrapper to list<int> (since you can't have an array of references), but this is probably more confusing than helpful:
template <typename List, typename... Lists>
std::array<std::reference_wrapper<List>, sizeof...(Lists) + 1>
as_array(List& x, Lists&... xs) {
return {x, xs...};
}
for (list<int>& l : as_array(a, b, c)) { // can't use auto, that deduces
l.sort(); // reference_wrapper<list<int>>,
} // so would need l.get().sort()
It is possible to write a function ref_range which allows you to do this:
for(auto& l : ref_range(a,b,c)) {
l.sort();
}
As others have said, once you write {a,b,c} you are stuck with an initializer_list, and such a list always takes copies of its arguments. The copies are const (hence your error), but even if you could get a non-const reference you would be modifying the copies of a, b and c instead of the originals.
Anyway, here is ref_range. It builds a vector of reference_wrapper.
// http://stackoverflow.com/questions/31724863/range-based-for-with-brace-initializer-over-non-const-values
#include<list>
#include<functional>
#include<array>
template<typename T, std:: size_t N>
struct hold_array_of_refs {
using vec_type = std:: array< std:: reference_wrapper<T>, N >;
vec_type m_v_of_refs;
hold_array_of_refs(vec_type && v_of_refs) : m_v_of_refs(std::move(v_of_refs)) { }
~hold_array_of_refs() { }
struct iterator {
typename vec_type :: const_iterator m_it;
iterator(typename vec_type :: const_iterator it) : m_it(it) {}
bool operator != (const iterator &other) {
return this->m_it != other.m_it;
}
iterator& operator++() { // prefix
++ this->m_it;
return *this;
}
T& operator*() {
return *m_it;
}
};
iterator begin() const {
return iterator(m_v_of_refs.begin());
}
iterator end() const {
return iterator(m_v_of_refs.end());
}
};
template<typename... Ts>
using getFirstTypeOfPack = typename std::tuple_element<0, std::tuple<Ts...>>::type;
template<typename ...T>
auto ref_range(T&... args) -> hold_array_of_refs< getFirstTypeOfPack<T...> , sizeof...(args)> {
return {{{ std:: ref(args)... }}}; // Why does clang prefer three levels of {} ?
}
#include<iostream>
int main(void){
std:: list<int> a,b,c;
// print the addresses, so we can verify we're dealing
// with the same objects
std:: cout << &a << std:: endl;
std:: cout << &b << std:: endl;
std:: cout << &c << std:: endl;
for(auto& l : ref_range(a,b,c)) {
std:: cout << &l << std:: endl;
l.sort();
}
}
The {...} syntax is actually creating an std::initializer_list. As the linked page states :
A std::initializer_list object is automatically constructed when:
[...]
a braced-init-list is bound to auto, including in a ranged for loop
And :
An object of type std::initializer_list<T> is a lightweight proxy object that provides access to an array of objects of type const T.
Thus, you can't modify the objects accessed through this initialize_list. Your solutions with the pointers looks like the easiest one to me.
Direct answer to your question:
Am I correctly guessing that brace-initializer is creating copy of
those lists?
Yes, this is the first problem. Your code would create copies of your lists, sort those copies, and finally forget the sorted copies.
However, that alone would just result in non-working code. The compiler error hints to a second problem: The implicit type of l is list<int> const&, rather than list<int>&. So the compiler complains that sort() tries to modify constant lists.
You can work around this second problem with a nasty const_cast:
#include <list>
#include <iostream>
using namespace std;
int main(void){
list<int> a,b,c;
a.push_back(2);
a.push_back(0);
a.push_back(1);
for(auto& l:{a,b,c}) const_cast<list<int>&>(l).sort();
for(auto i:a) cout << i << endl;
}
However, that will then trigger the first problem: Your list of lists contains copies, and only those copies are sorted. So the final output is not what you want:
2
0
1
The easiest workaround is to create a list of pointers to your lists:
#include <list>
#include <iostream>
using namespace std;
int main(void){
list<int> a,b,c;
a.push_back(2);
a.push_back(0);
a.push_back(1);
for(auto l:{&a,&b,&c}) l->sort();
for(auto i:a) cout << i << endl;
}
This will produce the desired result:
0
1
2
Others have already mentioned std::reference_wrapper, but they then used it to create an STL container instead of sticking with the brace-initializer list.
So all you need to do is:
for(auto& l:{std::ref(a),std::ref(b),std::ref(c)}) l.get().sort();
Of course, this is very similiar to the pointer solution already suggested.

Initializing non-static member array of size defined in a #define of class type without default ctor

I have the following class:
//in some .h file
#define BARS_IN_FOO 5 //The only place where this number should be specified.
//All code should work when I change this
//in some .cpp file
struct Foo;
struct Bar { Foo & foo; Bar(Foo & foo) : foo{ foo } {} } //Cannot be default initialized
struct Foo {
std::array<Bar, BARS_IN_FOO> myBars;
Foo() :
myBars{ } //Error. Cannot default initialize Bars.
//I want to initialize all Bars with Bar{*this} but at this point I don't
//know how many Bar initializers I should put in the myBar initializer list
{}
}
So how should I initialize Foo::myBars? The number of Bars is known at compile time but I just want to specify this number in one place (in the define preferably, other suggestions are welcome).
Usage of Foo::mybars:
Size of it will never change during runtime but I haven't decided what the number will be yet but will be somewhere in the range [1..10] (or so) (number might change a lot during development).
Element values will never change
(always will be the same non-const objects).
Relation ship between Foo and Bar is that of composition. A Foo is made out of Bars and their lifetime is the same. Bar without a Foo and visa versa makes no sense.
The Foo and Bar classes are part of performance critical code and their size will influence the memory footprint of the program a lot (80-90% of the memory footprint will be Foos and Bars).
Compiler: MSVS2017 version 15.3
Edit: Changing std::array<Bar, BARS_IN_FOO> myBars; to Bar myBars[BARS_IN_FOO]; is also oke if this helps.
Important edit: All the ctors of Bar and Foo are public. This was a mistake. I changed this.
You can do this pretty easily if you can assume that Bar is movable/copyable:
template <std::size_t ... Is>
std::array<Bar, sizeof...(Is)> make_bar_array_impl(Foo& f, std::index_sequence<Is...>) {
return { (Is, f)... };
}
template <std::size_t N>
std::array<Bar, N> make_bar_array(Foo& f) {
return make_bar_array_impl(f, std::make_index_sequence<N>{});
}
Foo() : myBars(make_bar_array<BARS_IN_FOO>(*this)) {}
This could easily refactored to use a more generic template metaprogramming utility of "repetition". I suspect that any template meta programming library will have some such utility, here I don't bother factoring it out since it is a one liner anyhow. But if you come across such problems often it's something to consider (just write a function that returns an N-entry initializer list all with the same expression).
Live example: http://coliru.stacked-crooked.com/a/aab004c0090cc144. Sorry couldn't easily access an MSVC compiler. Also compiled with 14 since I didn't need any 17 features.
Edit: even if Bar is not movable/copyable, or if you don't think things will get optimized, this technique can actually be modified to work even in that case. You can generate an array<std::reference_wrapper<Foo>, N instead. But this is a little bit more complex and typically in C++ most things should be movable, and usually constructor calls are not in the critical path. Still I can elaborate if necessary.
Edit2: also, please don't use a #define for that. constexpr static auto BARS_IN_FOO = 5; should work exactly the same way, except that it is properly namespaced (and probably some other macro nastiness I'm forgetting).
The solution is to build a char array (or a byte array in C++ 17) and use a pointer from there to have a Bar array. An union with a single Bar is enough to ensure proper alignment:
#include <iostream>
#define BARS_IN_FOO 5
// X is the type of the "array", Y the type of its initializer, n the size
template<class X, class Y = X, int n = 1>
class InitArr {
union {
X initial; // guarantee correct alignment
char buffer[n * sizeof(X)]; // only to reserve enough place
};
public:
InitArr(Y& inival): initial(inival) {
for (int i = 0; i < n; i++) {
new(&initial + i)X(inival); // properly construct an X at &initial +i
// which is guaranteed to be inside buffer
}
}
X& operator[] (int i) { // make InitArr behave like an array
X* arr = &initial;
return arr[i]; // could add control that 0 <= i < n
}
};
struct Foo;
struct Bar { Foo & foo; Bar(Foo & foo) : foo{ foo } {} }; //Cannot be default initialized
struct Foo {
InitArr<Bar, Foo, BARS_IN_FOO> myBars;
Foo() :
myBars{ *this }
//I want to initialize all Bars with Bar{*this}
{}
};
int main() {
Foo foo;
std::cout << &foo << std::endl;
// shows that all foo.myBars[i] point to the original foo
for (int i = 0; i < BARS_IN_FOO; i++) {
std::cout << &(foo.myBars[i].foo) << std::endl;
}
return 0;
}
As the X are constructed in place, everything is acceptable for any C++11 compiler and you get a true random access container. There is no Undefined Behaviour, because the memory was reserved by the char array, and the objects are correctly constructed there. This is a generic trick to delay a complex member initialization inside the constructor with the full power of the language, when thing become hard to do with a mere initializer or with compile time meta-programming.
Here is my original idea left here for reference but really less nice...
You could try to build a custom recursive array, to allow initialization of all of its elements from the same value:
// X is the type of the "array", Y the type of its initializer, n the size
template<class X, class Y=X, int n = 1>
class RArr {
public:
X first;
RArr<X, Y, n-1> other;
RArr(Y& i) : first(i), other(i) {}
X& operator [] (int i) {
if (i >= n || i < 0) throw std::domain_error("Out of range");
if (i == 0) return first;
return other[i - 1];
}
};
// specialization for n=1
template <class X, class Y>
class RArr<X, Y, 1> {
public:
X first;
RArr(Y& i) : first(i) {}
X& operator [] (int i) {
if (i != 0) throw std::domain_error("Out of range");
return first;
}
};
struct Foo;
struct Bar { Foo & foo; Bar(Foo & foo) : foo{ foo } {} }; //Cannot be default initialized
struct Foo {
RArr<Bar, Foo, BARS_IN_FOO> myBars;
Foo() :
myBars{ *this }
//I want to initialize all Bars with Bar{*this}
{}
};
int main() {
Foo foo;
std::cout << &foo << std::endl;
// shows that all foo.myBars[i] point to the original foo
for (int i = 0; i < BARS_IN_FOO; i++) {
std::cout << &(foo.myBars[i].foo) << std::endl;
}
return 0;
}
Well it works as per your requirements but is pretty useless as is because all the Bar elements refere to the same Foo. It will only make sense when Bar class will contain other members.

Implicitly cast wrapper class to supperclass in templated call

In designing a DSL (which compiles into C++), I found it convenient to define a wrapper class that, uppon destruction, would call a .free() method on the contained class:
template<class T>
class freeOnDestroy : public T {
using T::T;
public:
operator T&() const { return *this; }
~freeOnDestroy() { T::free(); }
};
The wrapper is designed to be completely transparent: All methods, overloads and constructors are inherited from T (at least to my knowledge), but when included in the wrapper, the free() method is called uppon destruction. Note that I explicitly avoid using T's destructor for this since T::free() and ~T() may have different semantics!
All this works fine, untill a wrapped class gets used as a member to a non-reference templated call, at which point freeOnDestroy is instantiated, calling free on the wrapped object. What I would like to happen is for the tempated method to use T instead of freeOnDestroy<T>, and to implicitly cast the parameter into the supperclass. The following code sample illustrates this problem:
// First class that has a free (and will be used in foo)
class C{
int * arr;
public:
C(int size){
arr = new int[size];
for (int i = 0; i < size; i++) arr[i] = i;
}
int operator[] (int idx) { return arr[idx]; }
void free(){ cout << "free called!\n"; delete []arr; }
};
// Second class that has a free (and is also used in foo)
class V{
int cval;
public:
V(int cval) : cval(cval) {}
int operator[] (int idx) { return cval; }
void free(){}
};
// Foo: in this case, accepts anything with operator[int]
// Foo cannot be assumed to be written as T &in!
// Foo in actuality may have many differently-templated parameters, not just one
template<typename T>
void foo(T in){
for(int i = 0; i < 5; i++) cout << in[i] << ' ';
cout << '\n';
}
int main(void){
C c(15);
V v(1);
freeOnDestroy<C> f_c(15);
foo(c); // OK!
foo(v); // OK!
foo<C>(f_c); // OK, but the base (C) of f_c may not be explicitly known at the call site, for example, if f_c is itself received as a template
foo(f_c); // BAD: Creates a new freeOnDestroy<C> by implicit copy constructor, and uppon completion calls C::free, deleting arr! Would prefer it call foo<C>
foo(f_c); // OH NO! Tries to print arr, but it has been deleted by previous call! Segmentation fault :(
return 0;
}
A few non solutions I should mention are:
Making freeOnDestroy::freeOnDestroy(const freeOnDestroy &src) explicit and private, but this seems to override T's constructor. I'd hoped it would try to implicitly convert it to T and use that as the template argument.
Assume foo receives a reference of its templated arguments (as in void foo(T &in): This is neither the case, nor desirable in some cases
Always explicitly template the call to foo, as in foo<C>(f_c): f_c itself may be templated, so it's hard to know to instantiate foo with C (yes, this could be done with creating multiple versions of foo, to remove the wrappers one by one, but I can't find a way of doing that without creating a different overload for each templated argument of foo).
In summary, my question is: Is there a clean(ish) method to ensure a base class will be casted to its superclass when resolving a template? Or, if not, is there some way of using SFINAE, by causing a substitution failure when the template argument is an instance of the wrapper class, and thus force it to use the implicit cast to the wrapped class (without duplicating each foo-like method signature possibly dozens of times)?
I presently have a work-arround that involves changes in the DSL, but I'm not entirely happy with it, and was curious if it was at all possible to design a wrapper class that works as described.
The problem here not when "wrapped class gets used as a member to a non-reference templated call".
The problem here is that the template wrapper -- and likely its superclass too -- has violated the Rule Of Three.
Passing an instance of the class as a non-reference parameter is just another way of saying "passing by value". Passing by value makes a copy of the instance of the class. Neither your template class -- nor its wrapped class, most likely -- has an explicit copy constructor; as such the copied instance of the class has no knowledge that it is a copy, hence the destructor does what it thinks it should do.
The correct solution here is not to hack something up that makes passing an instance of freeOnDestroy<T> by value end up copying T, rather than freeOnDestroy<T>. The correct solution is to add a proper copy-constructor and the assignment operator to both the freeOnDestroy template, and possibly any superclass that uses it, so that everything complies with the Rule Of Three.
You can use a properly defined detector and a sfinaed function, as it follows:
#include<iostream>
#include<type_traits>
template<class T>
class freeOnDestroy : public T {
using T::T;
public:
operator T&() const { return *this; }
~freeOnDestroy() { T::free(); }
};
template<typename T>
struct FreeOnDestroyDetector: std::false_type { };
template<typename T>
struct FreeOnDestroyDetector<freeOnDestroy<T>>: std::true_type { };
class C{
int * arr;
public:
C(int size){
arr = new int[size];
for (int i = 0; i < size; i++) arr[i] = i;
}
int operator[] (int idx) { return arr[idx]; }
void free(){ std::cout << "free called!\n"; delete []arr; }
};
class V{
int cval;
public:
V(int cval) : cval(cval) {}
int operator[] (int idx) { return cval; }
void free(){}
};
template<typename..., typename T>
std::enable_if_t<not FreeOnDestroyDetector<std::decay_t<T>>::value>
foo(T in) {
std::cout << "here you have not a freeOnDestroy based class" << std::endl;
}
template<typename..., typename T>
std::enable_if_t<FreeOnDestroyDetector<std::decay_t<T>>::value>
foo(T &in) {
std::cout << "here you have a freeOnDestroy based class" << std::endl;
}
int main(void){
C c(15);
V v(1);
freeOnDestroy<C> f_c(15);
foo(c);
foo(v);
foo<C>(f_c);
foo(f_c);
foo(f_c);
return 0;
}
As you can see by running the example, free is called only once, that is for the freeOnDestroy created in the main function.
If you want to forbid definitely freeOnDestroy as a parameter, you can use a single function as the following one:
template<typename..., typename T>
void foo(T &in) {
static_assert(not FreeOnDestroyDetector<std::decay_t<T>>::value, "!");
std::cout << "here you have a freeOnDestroy based class" << std::endl;
}
Note that I added a variadic parameter as a guard, so that one can no longer use foo<C>(f_c); to force a type to be used.
Remove it if you want to allow such an expression. It was not clear from the question.
One solution, which, although a little ugly, seems to work, is to use an overloaded unwrapping method, such as:
template<typename T> T freeOnDestroyUnwrapper(const T &in){ return in; }
template<typename T> T freeOnDestroyUnwrapper(const freeOnDestroy<T> &in){ return in; }
template<typename T> T freeOnDestroyUnwrapper(const freeOnDestroy<typename std::decay<T>::type> &in){ return in; }
template<typename T> T& freeOnDestroyUnwrapper(T &in){ return in; }
template<typename T> T& freeOnDestroyUnwrapper(freeOnDestroy<T> &in){ return in; }
template<typename T> T& freeOnDestroyUnwrapper(freeOnDestroy<typename std::decay<T>::type> &in){ return in; }
Then, calls can be made using the unwrapper:
int main(void){
C c(15);
V v(1);
freeOnDestroy<C> f_c(15);
foo(freeOnDestroyUnwrapper(c));
foo(freeOnDestroyUnwrapper(v));
foo<C>(freeOnDestroyUnwrapper(f_c));
foo(freeOnDestroyUnwrapper(f_c));
foo(freeOnDestroyUnwrapper(f_c));
return 0;
}
Or, to make this less verbose, we can alter foo so it does this for us:
template<typename T>
void _foo(T in){
for(int i = 0; i < 5; i++) cout << in[i] << ' ';
cout << '\n';
}
template<typename... Ts>
void foo(Ts&&... args){
_foo(freeOnDestroyUnwrapper(args)...);
}
And then call it as normal:
int main(void){
C c(15);
V v(1);
freeOnDestroy<C> f_c(15);
foo(c);
foo(v);
//foo<C>(f_c); // This now doesn't work!
foo(f_c);
foo(f_c);
return 0;
}
This seems to work for any number of arguments foo may have (of different templates, if needed), and seems to behave appropriately when foos input is a reference (which does not occur in my context, but would be good for the sake of making this solution generic).
I'm not convinced that this is the best solution, or that it generalizes to every case, plus, having to double all declarations is a bit cumbersome, and opaque to most IDEs autocomplete features. Better solutions and improvements are welcome!

Range-based for with brace-initializer over non-const values?

I am trying to iterate over a number of std::lists, sorting each of them. This is the naive approach:
#include<list>
using namespace std;
int main(void){
list<int> a,b,c;
for(auto& l:{a,b,c}) l.sort();
}
producing
aa.cpp:5:25: error: no matching member function for call to 'sort'
for(auto& l:{a,b,c}) l.sort();
~~^~~~
/usr/bin/../lib64/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/bits/stl_list.h:1586:7: note:
candidate function not viable: 'this' argument has type 'const
std::list<int, std::allocator<int> >', but method is not marked const
sort();
^
/usr/bin/../lib64/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/bits/stl_list.h:1596:9: note:
candidate function template not viable: requires 1 argument, but 0 were
provided
sort(_StrictWeakOrdering);
^
1 error generated.
Am I correctly guessing that brace-initializer is creating copy of those lists? And is there a way to not copy them, and make them modifiable inside the loop? (other than making list of pointers to them, which is my current workaround).
You are guessing correctly. std::initializer_list elements are always const (which makes sort()ing them impossible, as sort() is a non-const member function) and its elements are always copied (which would make sort()-ing them meaningless even if they weren't const). From [dcl.init.list], emphasis mine:
An object of type std::initializer_list<E> is constructed from an initializer list as if the implementation
allocated a temporary array of N elements of type const E, where N is the number of elements in the
initializer list. Each element of that array is copy-initialized with the corresponding element of the initializer
list, and the std::initializer_list<E> object is constructed to refer to that array. [ Note: A constructor
or conversion function selected for the copy shall be accessible (Clause 11) in the context of the initializer
list. —end note ] If a narrowing conversion is required to initialize any of the elements, the program is
ill-formed. [ Example:
struct X {
X(std::initializer_list<double> v);
};
X x{ 1,2,3 };
The initialization will be implemented in a way roughly equivalent to this:
const double __a[3] = {double{1}, double{2}, double{3}};
X x(std::initializer_list<double>(__a, __a+3));
assuming that the implementation can construct an initializer_list object with a pair of pointers. —end
example ]
There is no way to make them non-const or non-copied. The pointer solution works:
for (auto l : {&a, &b, &c}) l->sort();
because it's the pointer that's const, not the element it's pointing to. The other alternative would be to write a variadic function template:
template <typename... Lists>
void sortAll(Lists&&... lists) {
// before C++17
using expander = int[];
expander{0, (void(lists.sort()), 0)...};
// C++17 or later
(lists.sort(), ...);
}
sortAll(a, b, c);
You could also, I guess, write a helper to wrap your lists into an array of reference_wrapper to list<int> (since you can't have an array of references), but this is probably more confusing than helpful:
template <typename List, typename... Lists>
std::array<std::reference_wrapper<List>, sizeof...(Lists) + 1>
as_array(List& x, Lists&... xs) {
return {x, xs...};
}
for (list<int>& l : as_array(a, b, c)) { // can't use auto, that deduces
l.sort(); // reference_wrapper<list<int>>,
} // so would need l.get().sort()
It is possible to write a function ref_range which allows you to do this:
for(auto& l : ref_range(a,b,c)) {
l.sort();
}
As others have said, once you write {a,b,c} you are stuck with an initializer_list, and such a list always takes copies of its arguments. The copies are const (hence your error), but even if you could get a non-const reference you would be modifying the copies of a, b and c instead of the originals.
Anyway, here is ref_range. It builds a vector of reference_wrapper.
// http://stackoverflow.com/questions/31724863/range-based-for-with-brace-initializer-over-non-const-values
#include<list>
#include<functional>
#include<array>
template<typename T, std:: size_t N>
struct hold_array_of_refs {
using vec_type = std:: array< std:: reference_wrapper<T>, N >;
vec_type m_v_of_refs;
hold_array_of_refs(vec_type && v_of_refs) : m_v_of_refs(std::move(v_of_refs)) { }
~hold_array_of_refs() { }
struct iterator {
typename vec_type :: const_iterator m_it;
iterator(typename vec_type :: const_iterator it) : m_it(it) {}
bool operator != (const iterator &other) {
return this->m_it != other.m_it;
}
iterator& operator++() { // prefix
++ this->m_it;
return *this;
}
T& operator*() {
return *m_it;
}
};
iterator begin() const {
return iterator(m_v_of_refs.begin());
}
iterator end() const {
return iterator(m_v_of_refs.end());
}
};
template<typename... Ts>
using getFirstTypeOfPack = typename std::tuple_element<0, std::tuple<Ts...>>::type;
template<typename ...T>
auto ref_range(T&... args) -> hold_array_of_refs< getFirstTypeOfPack<T...> , sizeof...(args)> {
return {{{ std:: ref(args)... }}}; // Why does clang prefer three levels of {} ?
}
#include<iostream>
int main(void){
std:: list<int> a,b,c;
// print the addresses, so we can verify we're dealing
// with the same objects
std:: cout << &a << std:: endl;
std:: cout << &b << std:: endl;
std:: cout << &c << std:: endl;
for(auto& l : ref_range(a,b,c)) {
std:: cout << &l << std:: endl;
l.sort();
}
}
The {...} syntax is actually creating an std::initializer_list. As the linked page states :
A std::initializer_list object is automatically constructed when:
[...]
a braced-init-list is bound to auto, including in a ranged for loop
And :
An object of type std::initializer_list<T> is a lightweight proxy object that provides access to an array of objects of type const T.
Thus, you can't modify the objects accessed through this initialize_list. Your solutions with the pointers looks like the easiest one to me.
Direct answer to your question:
Am I correctly guessing that brace-initializer is creating copy of
those lists?
Yes, this is the first problem. Your code would create copies of your lists, sort those copies, and finally forget the sorted copies.
However, that alone would just result in non-working code. The compiler error hints to a second problem: The implicit type of l is list<int> const&, rather than list<int>&. So the compiler complains that sort() tries to modify constant lists.
You can work around this second problem with a nasty const_cast:
#include <list>
#include <iostream>
using namespace std;
int main(void){
list<int> a,b,c;
a.push_back(2);
a.push_back(0);
a.push_back(1);
for(auto& l:{a,b,c}) const_cast<list<int>&>(l).sort();
for(auto i:a) cout << i << endl;
}
However, that will then trigger the first problem: Your list of lists contains copies, and only those copies are sorted. So the final output is not what you want:
2
0
1
The easiest workaround is to create a list of pointers to your lists:
#include <list>
#include <iostream>
using namespace std;
int main(void){
list<int> a,b,c;
a.push_back(2);
a.push_back(0);
a.push_back(1);
for(auto l:{&a,&b,&c}) l->sort();
for(auto i:a) cout << i << endl;
}
This will produce the desired result:
0
1
2
Others have already mentioned std::reference_wrapper, but they then used it to create an STL container instead of sticking with the brace-initializer list.
So all you need to do is:
for(auto& l:{std::ref(a),std::ref(b),std::ref(c)}) l.get().sort();
Of course, this is very similiar to the pointer solution already suggested.

How to store either rvalue or lvalue references in template

I am trying to create a simple template enumerator class that should accept any object over which : operator is defined and later on print pairs of the form (i, v[i]). A simple implementation is the following:
template<typename T>
struct enumerator {
T &v; // reference to minimize copying
enumerator(T &_v) : v(_v) {}
void do_enumerate() {
size_t i = 0;
for(auto x : v) {
cout << i << x << endl;
i++;
}
}
};
This works ok for things like:
Case A
vector<int> v({1,2,6,2,4});
auto e = enumerator(v);
e.do_enumerate();
However, I would also like it to handle temporary objects like:
Case B
auto e = enumerator(vector<int>({2,3,9});
e.do_enumerate();
This does not work and the compiler throws:
no matching function for call to ‘enumerator<std::vector<int> >::enumerator(std::vector<int>)
So, I tried to then add a
enumerator(T _t) : t(_T) {}
constructor to resolve this error. Now case A does not work and there is an error:
error: call of overloaded ‘enumerator(std::vector<int>&)’ is ambiguous
Moreover, in case B, the output of the enumeration is not correct.
What is the cleanest way to solve this? I would
really like both cases to be working
prefer not to use any libraries other than stdc++
want as little copying as possible (thus just storing a T t in the struct is not an option)
C++11 is not a problem. I have g++-4.8, which I presume has complete enough C++11 support.
Well I would like to copy in case the argument is an rvalue, and not copy in case it is not. Is that possible?
This can be accomplished using a make_enumerator helper function as shown.
template <class T>
struct enumerator {
T v;
enumerator(T&& _v) : v(std::forward<T>(_v)) {}
void do_enumerate() {
size_t i = 0;
for(auto x : v) {
cout << i << x << endl;
i++;
}
}
};
template <class T>
enumerator<T> make_enumerator(T&& x) {
return enumerator<T>(std::forward<T>(x));
}
int main() {
vector<int> v {5, 2, 9, 1};
make_enumerator(v).do_enumerate();
make_enumerator(std::move(v)).do_enumerate();
}
How does this work?
If the argument to make_enumerator is an lvalue of type A then T is deduced as A& and we get the enumerator enumerator<A&>, whereas if it is an rvalue of type A then T is deduced as A and we get the enumerator enumerator<A>.
In the first case the member enumerator::v will have type A&, an lvalue reference that binds to the constructor argument (no copying). In the second case the member will have type A. The use of std::forward casts the parameter _v to an rvalue, so it will be moved from when it is used to initialize v.
This is a classic example where you don't actually need a class/struct (which actually introduce useless code) and you can just use good old functions:
template<typename Container>
void enumerate(const Container& t) {
std::size_t i = 0;
for(auto it = t.begin(); it != t.end(); ++it, ++i)
std::cout << i << *it << std::endl;
}
and then call it as:
enumerate(std::vector<int>{2,3,9});
Live demo
With this method you also get argument type inference for free (which you don't get with a struct).