I've been reading about std::forward and I think I understand it well, but I don't think I understand it well enough to use it proficiently enough.
I have a template class that implements a container and has a method called insert. I wanted this method to accept constant references and rvalue references so that if the inserted element is a rvalue reference, it is moved into the container, not copied. For this, I first overloaded the insert method like this:
template <typename U>
void do_some_work(U&& x) noexcept
{
m_data = std::forward<U>(x);
}
void insert(const T& x)
{
do_some_work(x);
}
void insert(T&& x) {
do_some_work(std::forward<T>(x);
}
The problem is, these two functions now have to call an "inner" function that implements the assertion. If the functions are small, I guess this is not a problem, but if they are large, it is best to use templates, like this
template <typename U>
void insert(U&& x)
{
do_some_work(std::forward<U>(x);
}
QUESTION 1: Is this correct?
Now, I want to do the same but with std::vector.
void insert_vector(const std::vector<T>& v) noexcept {
for (std::size_t i = 0; i < v.size(); ++i) {
do_some_work(v[i]);
}
}
void insert_vector(std::vector<T>&& v) noexcept
{
for (std::size_t i = 0; i < v.size(); ++i)
{
do_some_work(std::forward<T>(v[i]));
}
}
QUESTION 2: How do I collapse the insert_vector functions into a single one so that the call to do_some_work is done with
rvalue references when the vector is a rvalue reference (specified with std::move, for example),
constant reference when the vector is not given as an rvalue reference, like in (4) of the MWE below. The following does not work for me
template <typename U>
void insert_vector(U&& v) noexcept
{
for (std::size_t i = 0; i < v.size(); ++i)
{
do_some_work(std::forward<T>(v[i]));
}
}
Here is a minimum working example:
#include <iostream>
#include <vector>
template <typename T>
class my_class
{
private:
T m_data;
private:
template <typename U>
void do_some_more_work(U&& x) noexcept {
m_data = std::forward<U>(x);
}
template <typename U>
void do_some_work(U&& x) noexcept {
do_some_more_work(std::forward<U>(x));
}
public:
void insert(const T& x) noexcept {
std::cout << __PRETTY_FUNCTION__ << '\n';
do_some_work(x);
}
void insert(T&& x) noexcept {
std::cout << __PRETTY_FUNCTION__ << '\n';
do_some_work(std::forward<T>(x));
}
void insert_vector(const std::vector<T>& v) noexcept {
std::cout << __PRETTY_FUNCTION__ << '\n';
for (std::size_t i = 0; i < v.size(); ++i) {
do_some_work(v[i]);
}
}
void insert_vector(std::vector<T>&& v) noexcept {
std::cout << __PRETTY_FUNCTION__ << '\n';
for (std::size_t i = 0; i < v.size(); ++i) {
do_some_work(std::forward<T>(v[i]));
}
}
};
struct my_struct {
my_struct() noexcept = default;
my_struct(int v) noexcept : m_v(v) { }
my_struct(const my_struct& s) noexcept {
std::cout << __PRETTY_FUNCTION__ << '\n';
m_v = s.m_v;
}
my_struct(my_struct&& s) noexcept {
std::cout << __PRETTY_FUNCTION__ << '\n';
m_v = std::move(s.m_v); // not need, but whatever
s.m_v = -1;
}
my_struct& operator= (const my_struct& s) noexcept {
std::cout << __PRETTY_FUNCTION__ << '\n';
m_v = s.m_v;
return *this;
}
my_struct& operator= (my_struct&& s) noexcept {
std::cout << __PRETTY_FUNCTION__ << '\n';
m_v = std::move(s.m_v); // not need, but whatever
s.m_v = -1;
return *this;
}
int m_v;
};
int main() {
my_class<my_struct> mc;
std::cout << "===========================================\n";
{
std::cout << "-------------------------------------------\n";
std::cout << "(1.1)\n";
my_struct s{3};
std::cout << s.m_v << '\n';
mc.insert(s);
std::cout << s.m_v << '\n';
}
{
std::cout << "-------------------------------------------\n";
std::cout << "(1.2)\n";
const my_struct s{3};
std::cout << s.m_v << '\n';
mc.insert(s);
std::cout << s.m_v << '\n';
}
std::cout << "===========================================\n";
{
std::cout << "-------------------------------------------\n";
std::cout << "(2.1)\n";
mc.insert(my_struct{5});
}
{
std::cout << "-------------------------------------------\n";
std::cout << "(2.2)\n";
my_struct s{5};
std::cout << s.m_v << '\n';
mc.insert(std::move(s));
std::cout << s.m_v << '\n';
}
std::cout << "===========================================\n";
{
std::cout << "-------------------------------------------\n";
std::cout << "(3.1)\n";
std::vector<my_struct> v(5);
for (std::size_t i = 0; i < v.size(); ++i) { v[i] = my_struct(i); }
for (const auto& s : v) { std::cout << s.m_v << ' '; } std::cout << '\n';
mc.insert_vector(v);
for (const auto& s : v) { std::cout << s.m_v << ' '; } std::cout << '\n';
}
{
std::cout << "-------------------------------------------\n";
std::cout << "(3.2)\n";
const std::vector<my_struct> v = []() {
std::vector<my_struct> v(5);
for (std::size_t i = 0; i < v.size(); ++i) { v[i] = my_struct(i); }
return v;
}();
for (const auto& s : v) { std::cout << s.m_v << ' '; } std::cout << '\n';
mc.insert_vector(v);
for (const auto& s : v) { std::cout << s.m_v << ' '; } std::cout << '\n';
}
std::cout << "===========================================\n";
{
std::cout << "-------------------------------------------\n";
std::cout << "(4)\n";
std::vector<my_struct> v(5);
for (std::size_t i = 0; i < v.size(); ++i) { v[i] = my_struct(i); }
for (const auto& s : v) { std::cout << s.m_v << ' '; } std::cout << '\n';
mc.insert_vector(std::move(v));
for (const auto& s : v) { std::cout << s.m_v << ' '; } std::cout << '\n';
}
}
I think I found a way to solve this issue. I used the same "technique" as with the regular insert methods. The full implementation of my_class is this. Unfortunately, I could not make a single insert method.
template <typename T>
class my_class {
private:
T m_data;
private:
template <typename U>
void do_some_more_work(U&& x) noexcept {
std::cout << __PRETTY_FUNCTION__ << '\n';
m_data = std::forward<U>(x);
}
template <typename U>
void do_some_work(U&& x) noexcept {
std::cout << __PRETTY_FUNCTION__ << '\n';
do_some_more_work(std::forward<U>(x));
}
public:
template <typename U>
void insert(U&& x) noexcept {
std::cout << __PRETTY_FUNCTION__ << '\n';
do_some_work(std::forward<U>(x));
}
template <typename U>
void insert_vector(U&& v) noexcept {
using elem_t = typename std::remove_reference_t<U>::value_type;
// this is used here for testing purposes.
static_assert(std::is_same_v<elem_t, my_struct>);
std::cout << __PRETTY_FUNCTION__ << '\n';
for (std::size_t i = 0; i < v.size(); ++i) {
if constexpr (std::is_same_v<std::vector<elem_t>, U>) {
do_some_work(std::forward<T>(v[i]));
}
else {
do_some_work(v[i]);
}
}
}
};
Related
I am attempting to figure out how to move (or just copy if a move is not available) variadic parameters into a lambda within a templated function.
I am testing this with a move-only class (see below) because this would be the "worst-case" that needs to work with my template.
class MoveOnlyTest {
public:
MoveOnlyTest(int a, int b = 20, int c = 30) : _a(a), _b(b), _c(c) {
std::cout << "MoveOnlyTest: Constructor" << std::endl;
}
~MoveOnlyTest() {
std::cout << "MoveOnlyTest: Destructor" << std::endl;
}
MoveOnlyTest(const MoveOnlyTest& other) = delete;
MoveOnlyTest(MoveOnlyTest&& other) :
_a(std::move(other._a)),
_b(std::move(other._b)),
_c(std::move(other._c))
{
std::cout << "MoveOnlyTest: Move Constructor" << std::endl;
other._a = 0;
other._b = 0;
other._c = 0;
}
MoveOnlyTest& operator=(const MoveOnlyTest& other) = delete;
MoveOnlyTest& operator=(MoveOnlyTest&& other) {
if (this != &other) {
_a = std::move(other._a);
_b = std::move(other._b);
_c = std::move(other._c);
other._a = 0;
other._b = 0;
other._c = 0;
std::cout << "MoveOnlyTest: Move Assignment Operator" << std::endl;
}
return *this;
}
friend std::ostream& operator<<(std::ostream& os, const MoveOnlyTest& v) {
os << "{a=" << v._a << "}";
return os;
}
private:
int _a;
int _b;
int _c;
};
And here is the test code I am attempting to get working:
void test6() {
std::cout << "--------------------" << std::endl;
std::cout << " TEST 6 " << std::endl;
std::cout << "--------------------" << std::endl;
MoveOnlyTest v(1, 2, 3);
test6_A(std::move(v));
}
void test6_A(MoveOnlyTest v) {
std::cout << "test6_A()" << std::endl;
test6_B(test6_C, v);
}
template <typename ... ARGSF, typename ... ARGS>
void test6_B(void(*fn)(ARGSF...), ARGS&&... args) {
std::cout << "test6_B()" << std::endl;
//What do I need to get args to be moved/copied into the lambda
auto lambda = [fn, args = ???]() mutable {
(*fn)( std::forward<ARGS>(args)... );
};
lambda();
}
void test6_C(MoveOnlyTest v) {
std::cout << "test6_C()" << std::endl;
std::cout << "v = " << v << std::endl;
}
I am trying to have the exact same behavior as below, only using a generic template so that I can create a lambda which captures and arguments, and calls any function with those arguments.
void test5() {
std::cout << "--------------------" << std::endl;
std::cout << " TEST 5 " << std::endl;
std::cout << "--------------------" << std::endl;
MoveOnlyTest v(1, 2, 3);
test5_A(std::move(v));
}
void test5_A(MoveOnlyTest v) {
std::cout << "test5_A()" << std::endl;
auto lambda = [v = std::move(v)]() mutable {
test5_B(std::move(v));
};
lambda();
}
void test5_B(MoveOnlyTest v) {
std::cout << "test5_B()" << std::endl;
std::cout << "v = " << v << std::endl;
}
To be clear, I don't want to perfectly capture the arguments as in c++ lambdas how to capture variadic parameter pack from the upper scope I want to move them if possible and, if not, copy them (the reason being is that I plan to store this lambda for later execution thus the variables in the stack will no longer be around if they are just captured by reference).
To be clear, I don't want to perfectly capture the arguments as in c++
lambdas how to capture variadic parameter pack from the upper scope I
want to move them if possible
Just using the same form:
auto lambda = [fn, ...args = std::move(args)]() mutable {
(*fn)(std::move(args)...);
};
In C++17, you could do:
auto lambda = [fn, args = std::tuple(std::move(args)...)]() mutable {
std::apply([fn](auto&&... args) { (*fn)( std::move(args)...); },
std::move(args));
};
Is only the way to modify, not replace, an object stored as std::any is to declare changeable data mutable? E.g. to avoid creation and copy of class S instances:
#include <iostream>
#include <vector>
#include <any>
#include <string>
struct S {
mutable std::string str;
S(S&& arg) : str(std::move(arg.str)) { std::cout << ">> S moved" << std::endl; }
S(const S& arg) : str(arg.str) { std::cout << ">> S copied" << std::endl; }
S(const char *s) : str(s) { std::cout << ">> S created" << std::endl; }
S& operator= (const S& arg) { str = arg.str; return *this; }
S& operator= (S&& arg) { str = std::move(arg.str); return *this; }
virtual ~S() { std::cout << "<< S destroyed" << std::endl; }
};
int main() {
std::vector<std::any> container;
container.emplace_back(S("Test 1"));
std::any_cast<const S&>(container[0]).str = "Test 2";
for (const auto& a : container) {
std::cout << a.type().name() << ", "
<< std::any_cast<const S&>(a).str << std::endl;
}
}
You can any_cast with non-const reference:
std::any_cast<S&>(container[0]).str = "Test 2";
Demo
or
std::any a = 40;
std::any_cast<int&>(a) += 2;
std::cout << std::any_cast<int>(a) <<std::endl;
Demo
nope.
The issue is here.
std::any_cast<const S&>(container[0]).str = "Test 2";
you are trying to change constant data
Why b.isEm() prints different things on different lines when I have not changed anything after the last call of b.isEm()?
#include <iostream>
#include <string>
template <class T>
class Box
{
bool m_i;
T m_c;
public:
bool isEm() const;
void put(const T& c);
T get();
};
template <class T>
bool Box<T>::isEm() const
{
return m_i;
}
template <class T>
void Box<T>::put(const T& c)
{
m_i = false;
m_c = c;
}
template <class T>
T Box<T>::get()
{
m_i = true;
return T();
}
int main()
{
Box<int> b;
b.put(10);
std::cout << b.get() << " " << b.isEm() << std::endl;
std::cout << b.isEm() << std::endl;
}
The order of evaluation of function arguments in C++ is unspecified.
std::cout << b.get() << " " << b.isEm() << std::endl;
std::cout << b.isEm() << std::endl;
Since b.get() has side effects, I suggest you call it separately...
auto g = b.get();
std::cout << g << " " << b.isEm() << std::endl;
std::cout << b.isEm() << std::endl;
Note: std::cout << .... << ... << is a function call with the arguments ...
The destructor for List appears to work, but having trouble with the destructor for Element and List_iter:
Unhandled exception : 0xC00000FD: Stack overflow (parameters: 0x00000001, 0x002E2F78).
List:
#ifndef GUARD_List_h
#define GUARD_List_h
#include "Element.h"
#include "List_iter.h"
template <typename T>
class List {
public:
List() : begins(new Element<T>), ends(new Element<T>), Element_count(0) {
begins->t_flag = 'b';
ends->t_flag = 'e';
// double link: begins & ends
begins->next = ends;
ends->prev = begins;
}
virtual ~List() {
while (begins->next != ends) {
begins->prev = begins->next;
begins->next = begins->next->next;
delete begins->prev;
}
delete begins;
delete ends;
}
typedef List_iter<T> iterator;
iterator begin(void) const {
iterator it(begins);
return it;
}
iterator end(void) const {
iterator it(ends);
return it;
}
void push_back(const T val) {
Element<T>* elem = new Element<T>; // create: new-elem
elem->data = val; // set data
elem->prev = ends->prev; // link: new-elem to last-data-elem
ends->prev->next = elem; // link: last-data-elem to new-Element
elem->next = ends; // link: new-elem to List-end
ends->prev = elem; // link: List-end to new-elem
Element_count++; // update: when List grows
}
T at(const size_t pos) const {
return get_Element(pos)->data;
}
void del(const size_t pos) const {
Element<T>* elem = get_Element(pos); // get: Element for deletion
elem->prev->next = elem->next; // rejoin: double link
elem->next->prev = elem->prev; // rejoin: double link
delete elem;
Element_count--; // update: when List shrinks
}
void clear(void) {
Element<T>* ep = begins->next;
Element<T>* ep_next = ep->next;
while (ep->t_flag != 'e'){
delete ep;
ep = ep_next;
ep_next = ep->next;
}
begins->next = ends;
ends->prev = begins;
//begins->data = 0r;
//ends->elem_ID = 0;
Element_count = 0;
}
size_t size(void) const {
return Element_count;
}
bool empty(void) const {
if (Element_count == 0){ return true; }
else { return false; }
}
private:
Element<T>* begins; // List begins
Element<T>* ends; // List ends
size_t Element_count; // List size
Element<T>* get_Element(const size_t pos) const {
if (empty()) {
std::cerr << "No Element - Empty List";
throw;
}
if (pos < 0 || pos >= Element_count){
std::cerr << "No Element - Out of Range";
throw;
}
iterator it;
// Determine the more efficent iteration direction(forward or reverse) ?
if ((Element_count / 2) > pos) {
it = begin();
for (size_t i = 0; i <= pos; i++){
it++;
}
}
else {
it = end();
for (size_t i = size() - pos; i > 0; i--){
it--;
}
}
return it.elem;
}
};
#endif
Element:
#ifndef GUARD_Element_h
#define GUARD_Element_h
template <class T>
class List;
template <class T>
class List_iter;
template <class T>
class Element {
public:
Element() : prev(nullptr), next(nullptr), data(), t_flag(' ') {}
virtual ~Element() {
delete prev;
delete next;
}
friend List<T>;
friend List_iter<T>;
private:
Element<T> *prev;
Element<T> *next;
T data;
int elem_ID;
char t_flag;
};
#endif
List_iter:
#ifndef GUARD_List_iter_h
#define GUARD_List_iter_h
template <class T>
class List;
template <class T>
class List_iter {
public:
List_iter(Element<T>* e = nullptr) : elem(e) {}
virtual ~List_iter() {
delete elem;
}
friend List<T>;
T operator*(void){
if (elem->t_flag == 'e'){
elem = elem->prev;
}
else if (elem->t_flag == 'b'){
elem = elem->next;
}
return elem->data;
}
Element<T>* operator++(void) {
if (elem->next->t_flag == 'e'){
return nullptr;
}
elem = elem->next;
return elem;
}
Element<T>* operator--(void) {
if (elem->prev->t_flag == 'b'){
return nullptr;
}
elem = elem->prev;
return elem;
}
List_iter operator+(const int val) {
for (int i = 0; i < val; i++){
this->elem = this->elem->next;
}
return *this;
}
List_iter operator-(const int val) {
for (int i = 0; i < val; i++){
this->elem = this->elem->prev;
}
return *this;
}
bool operator!=(const List_iter& rhs) const {
return rhs.elem != elem;
}
bool operator>(const List_iter& rhs) const {
return (this->elem->elem_ID > rhs.elem->elem_ID);
}
bool operator<(const List_iter& rhs) const {
return (this->elem->elem_ID < rhs.elem->elem_ID);
}
bool operator>=(const List_iter& rhs) const {
return (this->elem->elem_ID >= rhs.elem->elem_ID);
}
bool operator<=(const List_iter& rhs) const {
return (this->elem->elem_ID <= rhs.elem->elem_ID);
}
private:
Element<T>* elem;
};
#endif
main:
#include <iostream>
#include "List.h"
int main() {
List<int> ls;
List<int>::iterator begin = ls.begin();
List<int>::iterator end = ls.end();
List<int>::iterator iter = begin;
std::cout << "Attempt to retrieve data from empty list: ls.at(3)" << std::endl;
std::cout << "--------------------------------------------------" << std::endl;
//std::cout << ls.at(3) << std::endl << std::endl;
std::cout << "Test: growing list does not invalidate iter" << std::endl;
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Empty list" << std::endl << std::endl;
std::cout << "begin addr: " << &begin << " " << std::endl;
std::cout << "end addr: " << &end << " " << std::endl;
std::cout << std::endl << "Add data to list: 33 " << std::endl << std::endl;
ls.push_back(33);
std::cout << "begin addr: " << &begin << " " << std::endl;
std::cout << "end addr: " << &end << " " << std::endl;
std::cout << std::endl << "Add data to list: 856 " << std::endl << std::endl;
ls.push_back(856);
std::cout << "begin addr: " << &begin << " " << std::endl;
std::cout << "end addr: " << &end << " " << std::endl;
std::cout << "clear() " << std::endl << std::endl;
ls.clear();
std::cout << std::endl << std::endl;
std::cout << "Add data to list: 0 1 2 3 4 5 6 7 8 9" << std::endl;
std::cout << "-------------------------------------------------" << std::endl;
for (int i = 0; i != 10; i++){
ls.push_back(i);
}
std::cout << std::endl << std::endl;
std::cout << "data# begin+4" << std::endl;
std::cout << "-------------" << std::endl;
std::cout << *(iter + 4) << std::endl;
std::cout << std::endl << std::endl;
std::cout << "data# begin->end" << std::endl;
std::cout << "----------------" << std::endl;
iter = begin;
while (iter++){
std::cout << *iter << " ";
}
std::cout << std::endl << std::endl << std::endl;
std::cout << "data# end->begin" << std::endl;
std::cout << "----------------" << std::endl;
iter = end;
while (iter--){
std::cout << *iter << " ";
}
std::cout << std::endl << std::endl << std::endl;
std::cout << "for/iter: begin->end" << std::endl;
std::cout << "----------------" << std::endl;
for (iter = begin; iter++;){
std::cout << *iter << " ";
}
std::cout << std::endl << std::endl << std::endl;
std::cout << "iter arith: +4 +1 -1" << std::endl;
std::cout << "--------------------" << std::endl;
iter = ls.begin();
iter = iter + 4;
std::cout << *iter << " ";
std::cout << *(iter + 1) << " ";
std::cout << *(iter - 1) << " ";
std::cout << std::endl << std::endl << std::endl;
std::cout << "data#: (0)(1)(2)(3)(4)(5)(6)(7)(8)(9)" << std::endl;
std::cout << "-------------------------------------" << std::endl;
for (int i = 0; i != 10; i++){
std::cout << ls.at(i) << " ";
}
//ls.clear();
List<std::string> ls_str;
ls_str.push_back("Hello");
ls_str.push_back("World");
return 0; // breakpoint
}
new Element called, therefore owned by List, so only List can delete Element. List_iter doesn't require a destructor because it only contains a pointer.
Please, could someone tell me how to switch the location of two elements from the same ptr_vector without
new dynamic memory allocation. That is, I want to do the same as below using std::vector, but with boost::ptr_vector.
Moreover, this has to be done using indexes, instead of ptr_vector::iterator.
void switch( vector<int>& V , size_t i , size_t j){
int a = V[ j ];
V[ j ] = V[ i ];
V[ i ] = a;
}
Thanks all.
(Untested), I'd imagine it has to be something like:
void switch( ptr_vector<int>& V , size_t i , size_t j){
auto p = V.replace(i, nullptr); // should get you the value there..
auto k = V.replace(j, p); // should get you the value there..
auto res = V.replace(i, k);
assert(res == nullptr); // this should be the case...
}
boost::ptr_vector<T> v;
size_t i = whatever, j = whatever;
// Put this in a separate function
// Do NOT use it as a subexpression or you may (?) forfeit exception safety
v.replace(j, v.replace(i, &v[j]).release()).release();
You can just swap the element values:
using std::swap;
swap(v[1], v[2]);
This will do exactly what you expected from the std::vector case. Here's a demo using a sentinel type to trace allocations: Live On Coliru (it doesn't do any new allocations for the swap)
Prints:
static void* X::operator new(size_t)(4)
X::X(int)(1)
static void* X::operator new(size_t)(4)
X::X(int)(2)
static void* X::operator new(size_t)(4)
X::X(int)(3)
static void* X::operator new(size_t)(4)
X::X(int)(4)
X[1] X[2] X[3] X[4]
===============================
swapping v[1] and v[2]:
X::X(X&&)(X[2])
X& X::operator=(X&&)(X[3])
X& X::operator=(X&&)(X[2])
X::~X()
===============================
X[1] X[3] X[2] X[4] X::~X()
static void X::operator delete(void*)
X::~X()
static void X::operator delete(void*)
X::~X()
static void X::operator delete(void*)
X::~X()
static void X::operator delete(void*)
Full Program
#include <boost/ptr_container/ptr_vector.hpp>
struct X {
X(int i) : _i(i) { std::cout << __PRETTY_FUNCTION__ << "(" << i << ")" << "\n"; }
X(X && x) : _i(x._i) { std::cout << __PRETTY_FUNCTION__ << "(" << x << ")" << "\n"; }
X(X const& x) : _i(x._i) { std::cout << __PRETTY_FUNCTION__ << "(" << x << ")" << "\n"; }
~X() { std::cout << __PRETTY_FUNCTION__ << "\n"; }
void* operator new(size_t n) {
std::cout << __PRETTY_FUNCTION__ << "(" << n << ")" << "\n";
return ::operator new(n);
}
void operator delete(void* px) {
std::cout << __PRETTY_FUNCTION__ << "\n";
return ::operator delete(static_cast<X*>(px));
}
X& operator=(X const& x) {
_i = x._i;
std::cout << __PRETTY_FUNCTION__ << "(" << x << ")" << "\n";
return *this;
}
X& operator=(X && x) {
_i = x._i;
std::cout << __PRETTY_FUNCTION__ << "(" << x << ")" << "\n";
return *this;
}
friend std::ostream& operator<<(std::ostream& os, X const& x) {
return os << "X[" << x._i << "]";
}
private: int _i;
};
int main()
{
boost::ptr_vector<X> v;
v.push_back(new X(1));
v.push_back(new X(2));
v.push_back(new X(3));
v.push_back(new X(4));
for (auto& p : v)
std::cout << p << " ";
std::cout << "\n===============================\nswapping v[1] and v[2]:\n";
using std::swap;
swap(v[1], v[2]);
std::cout << "\n===============================\n";
for (auto& p : v)
std::cout << p << " ";
}