Is there any library that provides containers for non-copyable types that are not valid by default?

I am looking for a library that provides containers such as std::array (fixed compile time, but without aggregate initialization support) and std::vector (variable size, continuous memory) that work for types that are not copied and not copied by default.

In particular, I want to be able to pass a set of functions to the constructor, which are used to get arguments for the constructors of the contained objects. Something like emplace_back , but as a constructor it uses lazily evaluated arguments.

Here is an example (naturally, it does not work):

 class stubborn_type : boost::noncopyable { public: explicit stubborn_type(int value) : value(value) {} private: const int value; }; struct generate_values { generate_values(int initial_value = 0) : current_value(initial_value) {} int operator()() { return current_value++; } private: int current_value; }; /* This should create a vector containing 10 elements initialized with the values [0..9] in order. */ magic::vector<stubborn_type> data(10, generate_values()); 

I need the solution to be compatible with C ++ 03 (since this means the absence of variation patterns, I would prefer to use the Boost method to use preprocessing magic to generate overloads for different numbers of arguments, but a reasonable fixed limit is good like Well). Does something like this exist? If not, are there libraries that would help achieve this goal (e.g. Boost.In Place Factory is almost useful, but lazy arguments don't support this).

+6
source share
1 answer

I do not know any ready-made solution, however, it is not so difficult to do. An array outline might look like this:

 #include <cstddef> typedef char saum; // smallest addressable unit of memory namespace magic { template<class T> class IArray { T *const _ptr; const size_t _length; public: operator T* () { return _ptr; } size_t length() const { return _length; } private: IArray<T>(T* ptr, size_t length) : _ptr(ptr), _length(length) {} template<class S, size_t length> friend class Array; }; template<class T> class Generator { public: virtual void operator() (T* place) = 0; }; template<class T, size_t length> class Array { saum buffer[sizeof(T) * length]; public: Array(Generator<T>& generate) { for (size_t i = 0; i < length; i++) generate((T*)buffer + i); } ~Array() { for (size_t i = 0; i < length; i++) ((T*)buffer)[i].~T(); } operator IArray<T> () { return IArray<T>((T*)buffer, length); } operator T* () { return (T*)buffer; } }; } 

I'm a little tired, so forgive me not thinking about the best names. However, he must do the job. Perhaps the solution of the generator is not too beautiful, but it gives flexibility. I believe that more feathers will not have a problem.

Example

 #include <new> #include <iostream> class Stubborn { public: Stubborn(int value) : value(value*2) { } const int value; private: Stubborn(const Stubborn&); Stubborn& operator=(const Stubborn&); }; struct StubbornGen : public magic::Generator<Stubborn> { StubbornGen() : current_value(0) {} void operator() (Stubborn* place) { new(place) Stubborn(current_value++); } private: int current_value; }; void f(magic::IArray<Stubborn> stubs) { std::cout << stubs[0].value << stubs[1].value << stubs[2].value << stubs[3].value << " " << stubs.length() << std::endl; } int main(int argc, char *argv[]) { StubbornGen gen; magic::Array<Stubborn, 4> stubs(gen); f(stubs); } 

Edit: Fixed, thanks to DyP, plus generator settings.

It is important to define the copy constructor and assignment operator for the array in order to avoid the problem indicated by DyP. -- How? - Depends on what you want. Making them private is one way. And making non-small copies is another. - In the second case, the template instance creation mechanism should prevent errors when applying a non-catalyzed class to an Array.

+2
source

Source: https://habr.com/ru/post/944122/


All Articles