
2013/2/13 Nevin Liber <nevin@eviloverlord.com>
On 12 February 2013 14:02, Krzysztof Czainski <1czajnik@gmail.com> wrote:
I am not familiar with C++11 initialization syntax details, I only read about that, and I'm stuck with C++03 for now. Are you suggesting, that this would mean adding a lot of (too many?) member functions?
There are some corner cases where list initialization behaves differently than direct initialization.
Take the following example:
template<typename T> struct ListInitializationAllocator { typedef T value_type; typedef typename std::aligned_storage<sizeof(T), alignof(T)>::type storage_type;
T* allocate(size_t n) { return static_cast<T*>(static_cast<void*>(::new storage_type[n])); } void deallocate(T* p, size_t) { ::delete [] static_cast<storage_type*>(static_cast<void*>(p)); }
template<typename... Args> void construct(T* c, Args&&... args) { ::new (static_cast<void*>(c)) T{ std::forward<Args>(args)... }; } };
vector<vector<int>> vd; vd.emplace_back(2); assert(2 == vd.back().size());
vector<vector<int>, ListInitializationAllocator<vector<int>>> vl; vl.emplace_back(2); assert(1 == vl.back().size());
The element in vd is a vector<int> of 2 elements which are value-initialized to 0. The element in vl is a vector<int> of 1 element copy-initialized to 2.
Thank you, Nevin, for the above example. I think I see your point now. Furthermore, it gives me an idea: On 12 February 2013 23:17, Krzysztof Czainski <1czajnik@gmail.com> wrote:
Or perhaps if not a new member function, maybe an overload for a noinit tag, used like so:
v.emplace_back( noinit );
With noinit defined in the library something like: struct noinit_t {}; noinit_t const noinit = {};
Since the emplace* functions just forward construction args to the Allocator, the above noinit overloads can be implemented by just supplying a user Allocator: #include <boost/container/vector.hpp> #include <boost/type_traits/is_pod.hpp> #include <boost/utility/enable_if.hpp> #include <iostream> using namespace std; struct noinit_t {}; noinit_t const noinit = {}; template < class T > struct MyAllocator : std::allocator<T> { using std::allocator<T>::construct; // for v.emplace_back(noinit); void construct( T* c, noinit_t/*, typename boost::enable_if< boost::is_pod<T> >::type* = 0*/ ) {} }; int main() { #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) namespace cont = std; #else namespace cont = boost::container; #endif cont::vector< int, MyAllocator<int> > vi; vi.emplace_back(5); vi.pop_back(); vi.emplace_back(noinit); assert( 0 != vi.back() ); } Does this make sense? It works with mingw-4.7.2, but unfortunately it doesn't compile with -std=c++11, any ideas why? I also tried the same trick with listinit_t and list initialization (code attached), as Nevin suggests above, but that also doesn't compile. I don't think this can be done for resize(), can it? Cheers, Kris