Возможно ли заполнить вектор элементами в его конструкторе с идеальной передачей?
Скажите, пожалуйста, возможно ли вызвать для объекта класса std::vector конструктор, который заполнит вектор заданным количеством элементов, каждый из которых конструируется не копированием, и не перемещением, а идеальной передачей параметров в конструктор конструируемых элементов?
Например:
class A
{
public:
A(const int x, const int y) {}
};
class B
{
public:
B(const int x, const int y)
:
A_{ x, y }
{}
private:
A A_;
};
int main()
{
std::vector<B> vec(10, 10, 10);// ?
return 0;
}
Ответы (2 шт):
У класса B - два параметра. А в main Вы пытаетесь туда передать три параметра. Что с этого ожидается - я не знаю. Но можно вот так
std::vector<B> vec{{10, 10}, {10,10} };
будет два объекта типа B векторе.
Но есть честный способ избавится от лишних конструкторов - emplace_back
std::vector<B> vec;
vec.reserve(10); // выделяем нужное кол-во памяти. Можно с запасом
vec.emplace_back(10,10); // и добавляем
vec.emplace_back(10,10);
vec.emplace_back(10,10);
vec.emplace_back(10,10);
vec.emplace_back(10,10);
Нужно использовать конструктор вектора с двумя итераторами, и передать туда кастомный итератор, у которого operator* возвращает класс с перегруженным operator B.
За счет обязательного copy elision, должно получиться ноль копирований и перемещений.
Итератор должен быть random-access, чтобы вектор сразу знал сколько нужно элементов, и не перевыделял память в конструкторе.
Perfect forwarding аргументов в конструктор делать нельзя, чтобы он из них ничего не переместил.
Писал на коленке, но вроде работает:
#include <cstddef>
#include <iostream>
#include <iterator>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
template <typename T> struct tag {};
template <typename T, typename ...P>
class ConstructingIterator
{
std::size_t count = 0;
struct Proxy
{
std::tuple<std::remove_reference_t<P> *...> params;
operator T() const
{
return std::apply([](auto *... params){return T(*params...);}, params);
}
};
Proxy proxy;
public:
using value_type = Proxy;
using pointer = const Proxy *;
using reference = const Proxy &;
using difference_type = std::ptrdiff_t;
using iterator_category = std::random_access_iterator_tag;
ConstructingIterator() {}
ConstructingIterator(std::size_t count, tag<T>, P &&... params)
: count(count), proxy{{¶ms...}}
{}
template <typename C>
C to()
{
return C(*this, ConstructingIterator());
}
reference operator*() const
{
return proxy;
}
pointer operator->() const
{
return &proxy;
}
ConstructingIterator &operator++()
{
count--;
return *this;
}
ConstructingIterator &operator--()
{
count++;
return *this;
}
ConstructingIterator operator++(int)
{
ConstructingIterator ret;
operator++();
return ret;
}
ConstructingIterator operator--(int)
{
ConstructingIterator ret;
operator--();
return ret;
}
// We don't need to separately define `!=` starting from C++20.
bool operator==(const ConstructingIterator &other) const
{
return count == other.count;
}
auto operator<=>(const ConstructingIterator &other) const
{
return other.count <=> count; // sic
}
ConstructingIterator &operator+=(difference_type d)
{
count -= d;
return *this;
}
ConstructingIterator &operator-=(difference_type d)
{
count += d;
return *this;
}
// We don't need to separately define `number +/- iterator` starting from C++20.
ConstructingIterator operator+(difference_type d) const
{
ConstructingIterator ret(*this);
ret += d;
return ret;
}
ConstructingIterator operator-(difference_type d) const
{
ConstructingIterator ret(*this);
ret -= d;
return ret;
}
difference_type operator-(const ConstructingIterator &other) const
{
return other.count - count; // sic
}
reference operator[](difference_type d) const
{
return *(*this + d);
}
};
struct A
{
A() {std::cout << "A()\n";}
A(const A &) {std::cout << "A(const A &)\n";}
A(A &&) {std::cout << "A(A &&)\n";}
A &operator=(const A &) {std::cout << "A &operator=(const A &)\n"; return *this;}
A &operator=(A &&) {std::cout << "A &operator=(A &&)\n"; return *this;}
~A() {std::cout << "~A()\n";}
int x = 0, y = 0;
A(int x, int y) : x(x), y(y) {std::cout << "A(" << x << "," << y << ")\n";}
};
int main()
{
std::vector<A> vec = ConstructingIterator(3, tag<A>{}, 10, 20).to<std::vector<A>>();
for (const A &a : vec)
std::cout << "[" << a.x << "," << a.y << "]\n";
}