Related
I have a class that contains a vector of vector. It is allocator aware. When trying to call the operator[] to store elements in a reference, Visual Studio 2015 fails to compile, AppleClang (latest) is fine with it.
I am unsure whether this is a bug or not, which compiler is right, or if there is some undefined behaviour somewhere in my code.
Here is a concise example, with everything as simple as possible.
#include <cstdlib>
#include <memory>
#include <new>
#include <vector>
/* Allocator */
template <class T>
struct my_allocator {
typedef T value_type;
my_allocator() = default;
template <class U>
constexpr my_allocator(const my_allocator<U>&) noexcept {
}
T* allocate(std::size_t n) {
if (n > std::size_t(-1) / sizeof(T))
throw std::bad_alloc();
if (auto p = static_cast<T*>(std::malloc(n * sizeof(T))))
return p;
throw std::bad_alloc();
}
void deallocate(T* p, std::size_t) noexcept {
std::free(p);
}
};
template <class T, class U>
bool operator==(const my_allocator<T>&, const my_allocator<U>&) {
return true;
}
template <class T, class U>
bool operator!=(const my_allocator<T>&, const my_allocator<U>&) {
return false;
}
/* Example Element */
struct X {
X() = default;
X(X&&) = default;
X& operator=(X&&) = default;
X(const X&) = delete;
X& operator=(const X&) = delete;
int test = 42;
};
/* Example Container Class */
template <class T, class Allocator = std::allocator<T>>
struct vec_of_vec {
using OuterAlloc = typename std::allocator_traits<
Allocator>::template rebind_alloc<std::vector<T, Allocator>>;
vec_of_vec(const Allocator& alloc = Allocator{})
: data(10, std::vector<T, Allocator>{ alloc },
OuterAlloc{ alloc }) {
for (int i = 0; i < 10; ++i) {
data[i].resize(42);
}
}
std::vector<T, Allocator>& operator[](size_t i) {
return data[i];
}
std::vector<std::vector<T, Allocator>, OuterAlloc> data;
};
/* Trigger Error */
int main(int, char**) {
my_allocator<X> alloc;
vec_of_vec<X, my_allocator<X>> test(alloc);
X& ref_test = test[0][0]; // <-- Error Here!
printf("%d\n", ref_test.test);
return 0;
}
VS tries to use the copy constructor of X.
error C2280: 'X::X(const X &)': attempting to reference a deleted function
function main.cpp(42): note: see declaration of 'X::X'
Is there something I am missing with the use of allocators and allocator_traits?
GCC error sheds light on what's going on, potentially same in VS2015 case.
In file included from memory:65,
from prog.cc:2:
bits/stl_uninitialized.h: In instantiation of '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = __gnu_cxx::__normal_iterator<const X*, std::vector<X, my_allocator<X> > >; _ForwardIterator = X*; _Allocator = my_allocator<X>]':
bits/stl_vector.h:454:31: required from 'std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = X; _Alloc = my_allocator<X>]'
bits/alloc_traits.h:250:4: required from 'static std::_Require<std::__and_<std::__not_<typename std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::type>, std::is_constructible<_Tp, _Args ...> > > std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::vector<X, my_allocator<X> >; _Args = {const std::vector<X, my_allocator<X> >&}; _Alloc = my_allocator<std::vector<X, my_allocator<X> > >; std::_Require<std::__and_<std::__not_<typename std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::type>, std::is_constructible<_Tp, _Args ...> > > = void]'
bits/alloc_traits.h:344:16: required from 'static decltype (std::allocator_traits<_Alloc>::_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::vector<X, my_allocator<X> >; _Args = {const std::vector<X, my_allocator<X> >&}; _Alloc = my_allocator<std::vector<X, my_allocator<X> > >; decltype (std::allocator_traits<_Alloc>::_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) = void]'
bits/stl_uninitialized.h:351:25: required from '_ForwardIterator std::__uninitialized_fill_n_a(_ForwardIterator, _Size, const _Tp&, _Allocator&) [with _ForwardIterator = std::vector<X, my_allocator<X> >*; _Size = long unsigned int; _Tp = std::vector<X, my_allocator<X> >; _Allocator = my_allocator<std::vector<X, my_allocator<X> > >]'
bits/stl_vector.h:1466:33: required from 'void std::vector<_Tp, _Alloc>::_M_fill_initialize(std::vector<_Tp, _Alloc>::size_type, const value_type&) [with _Tp = std::vector<X, my_allocator<X> >; _Alloc = my_allocator<std::vector<X, my_allocator<X> > >; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::value_type = std::vector<X, my_allocator<X> >]'
bits/stl_vector.h:421:9: required from 'std::vector<_Tp, _Alloc>::vector(std::vector<_Tp, _Alloc>::size_type, const value_type&, const allocator_type&) [with _Tp = std::vector<X, my_allocator<X> >; _Alloc = my_allocator<std::vector<X, my_allocator<X> > >; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::value_type = std::vector<X, my_allocator<X> >; std::vector<_Tp, _Alloc>::allocator_type = my_allocator<std::vector<X, my_allocator<X> > >]'
prog.cc:59:42: required from 'vec_of_vec<T, Allocator>::vec_of_vec(const Allocator&) [with T = X; Allocator = my_allocator<X>]'
prog.cc:76:46: required from here
bits/stl_uninitialized.h:275:25: error: no matching function for call to '__gnu_cxx::__alloc_traits<my_allocator<X>, X>::construct(my_allocator<X>&, X*, const X&)'
__traits::construct(__alloc, std::__addressof(*__cur), *__first);```
Wandbox
if we go from bottom to top we see:
vec_of_vec constructor
filling vector<vector> by 10 copies of empty inner vector
construction of copies
Despite of the fact that inner vector is empty, its copy constructor requires that the type it contains is copy-constructible.
P.S.
I don't know how clang overcomes this. Potentially it recognises that vector<vector> if filled with default value (if constructor with passed allocator instance still qualifies as default) and so instead of copying uses default construction
EDIT:
To fix the error replace
vec_of_vec(const Allocator& alloc = Allocator{})
: data(10, std::vector<T, Allocator>{ alloc },
OuterAlloc{ alloc }) {
for (int i = 0; i < 10; ++i) {
data[i].resize(42);
}
}
by
vec_of_vec(const Allocator& alloc = Allocator{})
{
data.resize(10); // here we don't `fill` it by copies but default-construct 10 instances
for (int i = 0; i < 10; ++i) {
data[i].resize(42);
}
}
or version for stateful allocator:
vec_of_vec(const Allocator& alloc = Allocator{}):
data(OuterAlloc(alloc))
{
for (int i = 0; i < 10; ++i) {
data.emplace_back(alloc);
data.back().resize(42);
}
}
I am implementing a map, and I would like to use std::rotate on an array of pairs, of which the first member is const (so that the key cannot be changed when inserted in the map). It is equivalent to the code below which doesn't compile:
#include <utility>
#include <array>
#include <algorithm>
int main()
{
typedef std::pair<const int, int> map_entry;
std::array<map_entry, 3> a{ { {2, 0}, {1, 0}, {3, 0} } };
std::rotate(&a[0], &a[1], &a[3]);
}
Unfortunately, I cannot control the type of the pair ("value_type") which needs to be defined as follows be compatible with std::unordered_map:
template <class K, class T, class H, class P, class A>
class unordered_map
{
public:
typedef K key_type;
typedef std::pair<const K, T> value_type;
typedef T mapped_type;
Is there way for me to use std::rotate on such an array, maybe by removing the const somehow?
Here is the compile error:
$ g++ -std=c++11 xx.cxx
In file included from /usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/utility:70:0,
from xx.cxx:1:
/usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/stl_pair.h: In instantiation of ‘std::pair<_T1, _T2>& std::pair<_T1, _T2>::operator=(std::pair<_T1 , _T2>&&) [with _T1 = const int; _T2 = int]’:
/usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/stl_algo.h:1610:22: required from ‘void std::__rotate(_RandomAccessIterator, _RandomAccessIterat or, _RandomAccessIterator, std::random_access_iterator_tag) [with _RandomAccessIterator = std::pair<const int, int>*]’
/usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/stl_algo.h:1686:59: required from ‘void std::rotate(_FIter, _FIter, _FIter) [with _FIter = std:: pair<const int, int>*]’
xx.cxx:9:36: required from here
/usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/stl_pair.h:170:8: error: assignment of read-only member ‘std::pair<const int, int>::first’
first = std::forward<first_type>(__p.first);
^
In file included from /usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/stl_pair.h:59:0,
from /usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/utility:70,
from xx.cxx:1:
/usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/move.h: In instantiation of ‘void std::swap(_Tp&, _Tp&) [with _Tp = const int]’:
/usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/stl_pair.h:199:23: required from ‘void std::pair<_T1, _T2>::swap(std::pair<_T1, _T2>&) [with _T1 = const int; _T2 = int]’
/usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/stl_pair.h:256:7: required from ‘void std::swap(std::pair<_T1, _T2>&, std::pair<_T1, _T2>&) [wit h _T1 = const int; _T2 = int]’
/usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/stl_algobase.h:147:22: required from ‘void std::iter_swap(_ForwardIterator1, _ForwardIterator2) [with _ForwardIterator1 = std::pair<const int, int>*; _ForwardIterator2 = std::pair<const int, int>*]’
/usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/stl_algo.h:1616:28: required from ‘void std::__rotate(_RandomAccessIterator, _RandomAccessIterat or, _RandomAccessIterator, std::random_access_iterator_tag) [with _RandomAccessIterator = std::pair<const int, int>*]’
/usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/stl_algo.h:1686:59: required from ‘void std::rotate(_FIter, _FIter, _FIter) [with _FIter = std:: pair<const int, int>*]’
xx.cxx:9:36: required from here
/usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/move.h:176:11: error: assignment of read-only reference ‘__a’
__a = _GLIBCXX_MOVE(__b);
^
/usr/lib/gcc/i686-pc-cygwin/4.8.2/include/c++/bits/move.h:177:11: error: assignment of read-only reference ‘__b’
__b = _GLIBCXX_MOVE(__tmp);
^
Simple: don't use std::pair. Design a class that has the semantics that you need and use that. In particular, don't make the data members const. Instead, make them private and write accessors to enforce const-ness. int first() const;, int second() const; and int& second(); are a good start. But they really should be named key() and value(), or something else that matches your design better.
I found my solution. Internally, I store the pair without the const (mutable_value_type), but I still define value_type with the const and this is what is returned when you dereference an iterator for example.
template <class K, class T, class H, class P, class A>
class unordered_map
{
public:
typedef K key_type;
typedef std::pair<const K, T> value_type;
typedef std::pair<K, T> mutable_value_type;
I've been looking around for a way to do this, and I'm not sure it's even possible. I've got a class in Java that takes an instance of a generically-typed interface as part of its constructor, and I'd like to recreate it in C++ (it's a utility class that is handy in many situations). To the best of my understanding, the closest equivalent to an interface in C++ is a pure virtual class, and the (somewhat) equivalent of generics is templates.
So let's say I have some classes defined as follows:
template<typename R>
class AnInterface
{
public:
virtual R run() = 0;
virtual ~AnInterface() {}
};
template<typename R>
class Processor
{
public:
Processor(std::vector<AnInterface<R>> toRun) : toRun(toRun) {}
std::vector<R> process() {
std::vector<R> res;
for(int i = 0; i < this->toRun.size(); ++i)
res.push_back(toRun[i].run());
return res;
}
private:
std::vector<AnInterface<R>> toRun;
};
class AnInstanceClass : public AnInterface<int>
{
int run() { return 1+1; }
};
I'd like to be able to do something like this with them:
int main()
{
std::vector<AnInterface<int>> toRun;
toRun.push_back(AnInstanceClass());
toRun.push_back(AnInstanceClass());
Processor<int> p(toRun);
std::vector<int> p.process();
}
Basically, have a class who's job is to take a list of objects, run them, and then return a list of their results, while being agnostic to the types of objects and results (assuming that the objects have a 'run' function). In Java, I accomplished this with generics and interfaces. I tried implementing the above solution in C++, but it doesn't compile and the compiler output is very cryptic, suggesting that I'm screwing up something very fundamental to the language. My C++ is a little rusty, so I'm not exactly sure what that is. How can something like this be implemented in C++?
Edit: Here's the error message when I try to compile the above code:
In file included from /usr/include/c++/4.8/vector:64:0,
from test.cpp:1:
/usr/include/c++/4.8/bits/stl_vector.h: In instantiation of ‘class std::vector<AnInterface<int> >’:
test.cpp:36:36: required from here
/usr/include/c++/4.8/bits/stl_vector.h:704:7: error: cannot allocate an object of abstract type ‘AnInterface<int>’
resize(size_type __new_size, value_type __x = value_type())
^
test.cpp:4:7: note: because the following virtual functions are pure within ‘AnInterface<int>’:
class AnInterface
^
test.cpp:7:19: note: R AnInterface<R>::run() [with R = int]
virtual R run() = 0;
^
test.cpp: In function ‘int main()’:
test.cpp:40:23: error: expected initializer before ‘.’ token
std::vector<int> p.process();
^
test.cpp: In instantiation of ‘Processor<R>::Processor(std::vector<AnInterface<R> >) [with R = int]’:
test.cpp:39:27: required from here
test.cpp:15:68: error: no matching function for call to ‘std::vector<int, std::allocator<int> >::vector(std::vector<AnInterface<int> >&)’
Processor(std::vector<AnInterface<R> > toRun) : toRun(toRun) {}
^
test.cpp:15:68: note: candidates are:
In file included from /usr/include/c++/4.8/vector:64:0,
from test.cpp:1:
/usr/include/c++/4.8/bits/stl_vector.h:398:9: note: template<class _InputIterator> std::vector<_Tp, _Alloc>::vector(_InputIterator, _InputIterator, const allocator_type&)
vector(_InputIterator __first, _InputIterator __last,
^
/usr/include/c++/4.8/bits/stl_vector.h:398:9: note: template argument deduction/substitution failed:
test.cpp:15:68: note: candidate expects 3 arguments, 1 provided
Processor(std::vector<AnInterface<R> > toRun) : toRun(toRun) {}
^
In file included from /usr/include/c++/4.8/vector:64:0,
from test.cpp:1:
/usr/include/c++/4.8/bits/stl_vector.h:310:7: note: std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = int; _Alloc = std::allocator<int>]
vector(const vector& __x)
^
/usr/include/c++/4.8/bits/stl_vector.h:310:7: note: no known conversion for argument 1 from ‘std::vector<AnInterface<int> >’ to ‘const std::vector<int, std::allocator<int> >&’
/usr/include/c++/4.8/bits/stl_vector.h:295:7: note: std::vector<_Tp, _Alloc>::vector(std::vector<_Tp, _Alloc>::size_type, const value_type&, const allocator_type&) [with _Tp = int; _Alloc = std::allocator<int>; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::value_type = int; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<int>]
vector(size_type __n, const value_type& __value = value_type(),
^
/usr/include/c++/4.8/bits/stl_vector.h:295:7: note: no known conversion for argument 1 from ‘std::vector<AnInterface<int> >’ to ‘std::vector<int, std::allocator<int> >::size_type {aka long unsigned int}’
/usr/include/c++/4.8/bits/stl_vector.h:256:7: note: std::vector<_Tp, _Alloc>::vector(const allocator_type&) [with _Tp = int; _Alloc = std::allocator<int>; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<int>]
vector(const allocator_type& __a)
^
/usr/include/c++/4.8/bits/stl_vector.h:256:7: note: no known conversion for argument 1 from ‘std::vector<AnInterface<int> >’ to ‘const allocator_type& {aka const std::allocator<int>&}’
/usr/include/c++/4.8/bits/stl_vector.h:248:7: note: std::vector<_Tp, _Alloc>::vector() [with _Tp = int; _Alloc = std::allocator<int>]
vector()
^
/usr/include/c++/4.8/bits/stl_vector.h:248:7: note: candidate expects 0 arguments, 1 provided
In file included from /usr/include/c++/4.8/vector:69:0,
from test.cpp:1:
/usr/include/c++/4.8/bits/vector.tcc: In instantiation of ‘void std::vector<_Tp, _Alloc>::_M_insert_aux(std::vector<_Tp, _Alloc>::iterator, const _Tp&) [with _Tp = AnInterface<int>; _Alloc = std::allocator<AnInterface<int> >; std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<AnInterface<int>*, std::vector<AnInterface<int> > >; typename std::_Vector_base<_Tp, _Alloc>::pointer = AnInterface<int>*]’:
/usr/include/c++/4.8/bits/stl_vector.h:913:28: required from ‘void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = AnInterface<int>; _Alloc = std::allocator<AnInterface<int> >; std::vector<_Tp, _Alloc>::value_type = AnInterface<int>]’
test.cpp:37:38: required from here
/usr/include/c++/4.8/bits/vector.tcc:329:19: error: cannot allocate an object of abstract type ‘AnInterface<int>’
_Tp __x_copy = __x;
^
test.cpp:4:7: note: since type ‘AnInterface<int>’ has pure virtual functions
class AnInterface
^
In file included from /usr/include/c++/4.8/vector:69:0,
from test.cpp:1:
/usr/include/c++/4.8/bits/vector.tcc:329:8: error: cannot declare variable ‘__x_copy’ to be of abstract type ‘AnInterface<int>’
_Tp __x_copy = __x;
^
test.cpp:4:7: note: since type ‘AnInterface<int>’ has pure virtual functions
class AnInterface
^
In file included from /usr/include/x86_64-linux-gnu/c++/4.8/bits/c++allocator.h:33:0,
from /usr/include/c++/4.8/bits/allocator.h:46,
from /usr/include/c++/4.8/vector:61,
from test.cpp:1:
/usr/include/c++/4.8/ext/new_allocator.h: In instantiation of ‘void __gnu_cxx::new_allocator<_Tp>::construct(__gnu_cxx::new_allocator<_Tp>::pointer, const _Tp&) [with _Tp = AnInterface<int>; __gnu_cxx::new_allocator<_Tp>::pointer = AnInterface<int>*]’:
/usr/include/c++/4.8/ext/alloc_traits.h:216:9: required from ‘static void __gnu_cxx::__alloc_traits<_Alloc>::construct(_Alloc&, __gnu_cxx::__alloc_traits<_Alloc>::pointer, const _Tp&) [with _Tp = AnInterface<int>; _Alloc = std::allocator<AnInterface<int> >; __gnu_cxx::__alloc_traits<_Alloc>::pointer = AnInterface<int>*]’
/usr/include/c++/4.8/bits/stl_vector.h:906:34: required from ‘void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = AnInterface<int>; _Alloc = std::allocator<AnInterface<int> >; std::vector<_Tp, _Alloc>::value_type = AnInterface<int>]’
test.cpp:37:38: required from here
/usr/include/c++/4.8/ext/new_allocator.h:130:9: error: cannot allocate an object of abstract type ‘AnInterface<int>’
{ ::new((void *)__p) _Tp(__val); }
^
test.cpp:4:7: note: since type ‘AnInterface<int>’ has pure virtual functions
class AnInterface
^
In file included from /usr/include/c++/4.8/vector:62:0,
from test.cpp:1:
/usr/include/c++/4.8/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, const _T2&) [with _T1 = AnInterface<int>; _T2 = AnInterface<int>]’:
/usr/include/c++/4.8/bits/stl_uninitialized.h:75:53: required from ‘static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const AnInterface<int>*, std::vector<AnInterface<int> > >; _ForwardIterator = AnInterface<int>*; bool _TrivialValueTypes = false]’
/usr/include/c++/4.8/bits/stl_uninitialized.h:117:41: required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const AnInterface<int>*, std::vector<AnInterface<int> > >; _ForwardIterator = AnInterface<int>*]’
/usr/include/c++/4.8/bits/stl_uninitialized.h:258:63: required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = __gnu_cxx::__normal_iterator<const AnInterface<int>*, std::vector<AnInterface<int> > >; _ForwardIterator = AnInterface<int>*; _Tp = AnInterface<int>]’
/usr/include/c++/4.8/bits/stl_vector.h:316:32: required from ‘std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = AnInterface<int>; _Alloc = std::allocator<AnInterface<int> >]’
test.cpp:39:27: required from here
/usr/include/c++/4.8/bits/stl_construct.h:83:7: error: cannot allocate an object of abstract type ‘AnInterface<int>’
::new(static_cast<void*>(__p)) _T1(__value);
^
test.cpp:4:7: note: since type ‘AnInterface<int>’ has pure virtual functions
class AnInterface
You're basically (attempting to) re-create the functionality of std::generate. The difference is that generate doesn't rely on the somewhat clunky convention of a member function named run. Rather, it invokes something like a function (though it may, and often will, be an overloaded operator()).
We can also (frequently) avoid the separate definition of what you've named AnInstanceClass by defining the class in a lambda expression.
So, in this case, we'd be looking at something like:
std::vector<int> p;
std::generate_n(std::back_inserter(p), 2, [] { return 1 + 1; });
This is basically threading-agnostic, so if you want to run the individual tasks in separate threads, you can do that pretty easily as well. There are some caveats with std::async, but they're pretty much the same regardless of whether you involve std::generate.
Note that this is slightly different from #Severin's answer--he's mentioning std::transform instead of std::generate. The basic difference between the two is that transform takes a set of inputs, transforms them, and produces a set of those outputs. Your AnInstance::run just produces outputs (without taking any inputs) so at least to me it seems like std::generate is a better fit.
std::transform would be more useful if you had something like this:
std::vector<int> inputs { 1, 2, 3, 4, 5};
std::vector<int> results;
std::transform(inputs.begin(), inputs.end(), [](int in) { return in * 2; });
This should produce results of 2, 4, 6, 8, 10.
The only conceptual error you have is trying to get polymorphic behaviour when invoking virtual functions through objects, as opposed to pointers or references to said objects. In C++, to get run-time polymorphism, you need to work with pointers or references. Thus, Processor should work with a std::vector<AnInterface<R>*> like this:
template<typename R>
class Processor
{
public:
Processor(std::vector<AnInterface<R>*> toRun) : toRun(toRun) {}
std::vector<R> process() {
std::vector<R> res;
for(int i = 0; i < this->toRun.size(); ++i)
res.push_back(toRun[i]->run());
return res;
}
private:
std::vector<AnInterface<R>*> toRun;
};
Here's a fixed version of your code.
Another thing to note : when using overriding a virtual function in a derived class, mark the override with the eponymous keyword. This helps the compiler help you.
Do you really need Processor class? What I would propose to use std::transform
std::transform applies the given function to a range and stores the result in another range
vector<AnInterface<R>> does not work because it causes slicing. This is also the cause of your error messages, because some vector operations require to default-construct or copy-construct objects and that is not possible with an abstract class.
Probably vector<shared_ptr<AnInterface<R>>> best matches your intent. shared_ptr is the closest thing C++ has to a Java object reference.
Here is working code in C++11 based on your sample code. One point I would have is that Processor currently takes its vector by value. It could take this by reference, or even by moving, if that better matched your design.
#include <iostream>
#include <memory>
#include <vector>
template<typename R>
struct AnInterface
{
virtual R run() = 0;
virtual ~AnInterface() {}
};
template<typename R>
using AnInterfaceVector = std::vector< std::shared_ptr<AnInterface<R>> >;
template<typename R>
class Processor
{
public:
Processor(AnInterfaceVector<R> toRun) : toRun(toRun) {}
std::vector<R> process()
{
std::vector<R> res;
for (auto && r : toRun)
res.push_back( r->run() );
return res;
}
private:
AnInterfaceVector<R> toRun;
};
struct AnInstanceClass : AnInterface<int>
{
int run() override { return temp; }
AnInstanceClass(int n): temp(n) {}
int temp;
};
int main()
{
AnInterfaceVector<int> toRun;
toRun.emplace_back( std::make_shared<AnInstanceClass>(4) );
toRun.emplace_back( std::make_shared<AnInstanceClass>(7) );
Processor<int> p{toRun};
auto results = p.process();
for (auto && i : results)
std::cout << i << " ";
std::cout << std::endl;
}
NB. I don't offer any claim whether this is better or worse than using a different pattern as other answers have suggested; this is just a working version of the code you were trying to write.
As was already mentioned in the other answers, your error was trying to use a vector of interfaces (std::vector<AnInterface<int>>) instead of a vector of pointers to interfaces like std::vector<AnInterface<int>*> - with only the latter allowing polymorphism, whereas your version would try to store actual Interface objects (which is of course not posssible as they are abstract classes).
I wanted to mention in addition, that there is a nice pattern by Sean Parent that makes it unnecessary for your AnInstanceClass to inhereit from anything, as long as it implements a member function with the correct name and signature. This is quite handy, because you can e.g. even use lambdas or plain functions (after wrapping them in a std::function) which cannot inherit from anything:
#include <vector>
#include <memory>
#include <iostream>
#include <algorithm>
#include <functional>
//R is the return type
template<class R>
class Processor {
public:
//T can be anything, that has an ()-operator
template<class T>
void push_back(const T& arg) {
todo.emplace_back(std::make_unique<runnable_imp<T>>(arg));
}
std::vector<R> process() {
std::vector<R> ret;
for (auto& e : todo) {
ret.push_back(e->run());
}
return ret;
}
private:
struct runnable_concept {
virtual R run()=0;
virtual ~runnable_concept(){};
};
template<class T>
struct runnable_imp :public runnable_concept {
runnable_imp(T data) :data(data){};
virtual R run() override { return data(); }
T data;
};
std::vector<std::unique_ptr<runnable_concept>> todo;
};
struct SomeClass {
SomeClass(int arg) :arg(arg){};
int operator()(){ return arg; }
int arg;
};
int SomeFunction(){ return 30; }
int main()
{
Processor<int> pr;
pr.push_back([]{return 10; });
pr.push_back(SomeClass(20));
pr.push_back(std::function<int()>(SomeFunction));
std::vector<int> res= pr.process();
for (auto e : res) {
std::cout << e << std::endl;
}
}
Below is a condensed version of my code that gives me a compiler error. The compiler tells me to put typename in front of 'std::deque::reverse_iterator', which makes sense. But if I do I receive the error at the bottom. What does it mean? How can it be resolved?
#include <iostream>
#include <deque>
template<class T>
class Stack{
public:
Stack(){}
~Stack(){}
void push(T c) { s.push_back(c); }
void inspect() const{
for(typename std::deque<T>::reverse_iterator i=s.rbegin(); i!=s.rend(); i++)
std::cout << *i << std::endl;
}
private:
typename std::deque<T> s;
};
int main(){
Stack<int> s;
s.push(1);
s.inspect();
return 0;
}
Error:
error: no matching function for call to 'std::_Deque_iterator<int, int&, int*>::_Deque_iterator(std::reverse_iterator<std::_Deque_iterator<int, const int&, const int*> >::iterator_type)'|
note: candidates are:|
note: std::_Deque_iterator<_Tp, _Ref, _Ptr>::_Deque_iterator(const iterator&) [with _Tp = int; _Ref = int&; _Ptr = int*; std::_Deque_iterator<_Tp, _Ref, _Ptr>::iterator = std::_Deque_iterator<int, int&, int*>]|
note: no known conversion for argument 1 from 'std::reverse_iterator<std::_Deque_iterator<int, const int&, const int*> >::iterator_type {aka std::_Deque_iterator<int, const int&, const int*>}' to 'const iterator& {aka const std::_Deque_iterator<int, int&, int*>&}'|
note: std::_Deque_iterator<_Tp, _Ref, _Ptr>::_Deque_iterator() [with _Tp = int; _Ref = int&; _Ptr = int*]|
note: candidate expects 0 arguments, 1 provided|
note: std::_Deque_iterator<_Tp, _Ref, _Ptr>::_Deque_iterator(_Tp*, std::_Deque_iterator<_Tp, _Ref, _Ptr>::_Map_pointer) [with _Tp = int; _Ref = int&; _Ptr = int*; std::_Deque_iterator<_Tp, _Ref, _Ptr>::_Map_pointer = int**]|
note: candidate expects 2 arguments, 1 provided|
There's nothing dependent about std::deque<T>, so there mustn't be a typename. Only things to the right of a :: where the left depends on a template parameter is dependent.
This is a good example of where using auto would help you more than just saving typing. You're in a const member function, but trying to use your data member's reverse_iterator, not const_reverse_iterator.
Change typename std::deque<T>::reverse_iterator to typename std::deque<T>::const_reverse_iterator, or, more simply, auto.
This is in addition to the extra typename on your data member.
One can push_back rvalues of a noncopyable-but-movable type into a vector of that type:
#include <vector>
struct S
{
S(int);
S(S&&);
};
int main()
{
std::vector<S> v;
v.push_back(S(1));
v.push_back(S(2));
v.push_back(S(3));
}
However, when I try to initializer-list-construct the vector with the same rvalues, I get errors about a copy constructor being required:
#include <vector>
struct S
{
S(int);
S(S&&);
};
int main()
{
std::vector<S> v = {S(1), S(2), S(3)};
}
I get the following errors with GCC 4.7:
In file included from include/c++/4.7.0/vector:63:0,
from test.cpp:1:
include/c++/4.7.0/bits/stl_construct.h: In instantiation of 'void std::_Construct(_T1*, _Args&& ...) [with _T1 = S, _Args = {const S&}]':
include/c++/4.7.0/bits/stl_uninitialized.h:77:3: required from 'static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = const S*, _ForwardIterator = S*, bool _TrivialValueTypes = false]'
include/c++/4.7.0/bits/stl_uninitialized.h:119:41: required from '_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = const S*, _ForwardIterator = S*]'
include/c++/4.7.0/bits/stl_uninitialized.h:260:63: required from '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = const S*, _ForwardIterator = S*, _Tp = S]'
include/c++/4.7.0/bits/stl_vector.h:1185:4: required from 'void std::vector<_Tp, _Alloc>::_M_range_initialize(_ForwardIterator, _ForwardIterator, std::forward_iterator_tag) [with _ForwardIterator = const S*, _Tp = S, _Alloc = std::allocator<S>]'
include/c++/4.7.0/bits/stl_vector.h:362:2: required from 'std::vector<_Tp, _Alloc>::vector(std::initializer_list<_Tp>, const allocator_type&) [with _Tp = S, _Alloc = std::allocator<S>, std::vector<_Tp, _Alloc>::allocator_type = std::allocator<S>]'
test.cpp:11:41: required from here
include/c++/4.7.0/bits/stl_construct.h:77:7: error: no matching function for call to 'S::S(const S&)'
include/c++/4.7.0/bits/stl_construct.h:77:7: note: candidates are:
test.cpp:6:5: note: S::S(S&&)
test.cpp:6:5: note: no known conversion for argument 1 from 'const S' to 'S&&'
test.cpp:5:5: note: S::S(int)
test.cpp:5:5: note: no known conversion for argument 1 from 'const S' to 'int'
Should this be allowed? I see no technical obstacles to it being allowed, but I don't have the Standard handy at the moment...
Maybe this clause from 8.5.4.5 explains it (my emphasis):
An object of type std::initializer_list is constructed from an
initializer list as if the implementation allocated an array of N
elements of type 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 object is constructed to refer to that array.
So you can only initialize from lists if the objects are copyable.
Update: As Johannes points out, copy-initialization can be realized by both copy and move constructors, so that alone isn't enough to answer the question. Here is, however, an excerpt of the specification of the initializer_list class as described in 18.9:
template<class _E>
class initializer_list
{
public:
typedef _E value_type;
typedef const _E& reference;
typedef const _E& const_reference;
typedef size_t size_type;
typedef const _E* iterator;
typedef const _E* const_iterator;
Note how there are no non-constant typedefs!
I just tried making an IL constructor which would traverse the initializer list via std::make_move_iterator, which failed because const T & cannot be converted to T&&.
So the answer is: You cannot move from the IL, because the standard says so.
The initializer_list only provides const references and const iterators. There is no way for the vector to move from that.
template<class E>
class initializer_list {
public:
typedef E value_type;
typedef const E& reference;
typedef const E& const_reference;
typedef size_t size_type;
typedef const E* iterator;
typedef const E* const_iterator;
It appears it might be a compiler issue. This works in g++ 4.5.1 (click for IdeOne online demo)
Conclusion: It was, in the sense that older g++ implementations did not correctly flag an error; initializer lists do not support moving their elements (elements are implicitely copied in the process). Thank to Kerrek SB for quoting the helpful phrase from the standard.
Old proceedings (for the sake of understanding the comments:)
Edit Found out that at least g++ 4.6.1+ seem to have your complaint about this code.
Edit Upon reading the source to std::initializer_list<T> I'm starting to get the impression that this is not supported by the library (it looks intentional). Whether the standard actually allows for an initializer list to forward the xvalue-ness of it's elements... I wouldn't be surprised if they stopped there (perfect forwarding is still not easily supported in C++0x I think, and not all initializer parameters would need to have the same (deductable) type.
Anyone with more standardese under his belt care to help out? http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2640.pdf
#include <vector>
struct S
{
S(int) {};
S(S&&) {};
};
int main()
{
std::vector<S> v = {S(1), S(2), S(3)};
std::vector<S> w = {std::move(S(1)), std::move(S(2)), std::move(S(3))};
std::vector<S> or_even_just = {1, 2, 3};
}
It seems the answer is No per Kerrek SB's answer. But you can achieve something similar by small helper functions using variadic templates:
#include <vector>
#include <utility>
template <typename T>
void add_to_vector(std::vector<T>* vec) {}
template <typename T, typename... Args>
void add_to_vector(std::vector<T>* vec, T&& car, Args&&... cdr) {
vec->push_back(std::forward<T>(car));
add_to_vector(vec, std::forward<Args>(cdr)...);
}
template <typename T, typename... Args>
std::vector<T> make_vector(Args&&... args) {
std::vector<T> result;
add_to_vector(&result, std::forward<Args>(args)...);
return result;
}
struct S {
S(int) {}
S(S&&) {}
};
int main() {
std::vector<S> v = make_vector<S>(S(1), S(2), S(3));
return 0;
}