Тебе нужна глубокая, а не поверхностная константность. С аналогичной проблемой столкнёшься, если будешь вместо голой ссылки или использовать указатели (голые, умные, std::reference_wrapper — не существенно; семантика указателя обычно предполагает поверхностную константность).
Её можно сделать, например, так
template<class T> class reference
{
private:
T* ptr_; // заодно избавимся от голой ссылки, ломающей модель Assignable на корнюpublic:
reference(T& ref) : ptr_(&ref) {}
T& get() { return *ptr_; }
T const& get() const { return *ptr_; }
// неявное приведение к T& / const T& - по вкусу.operator T&() { return get(); }
operator T const&() const { return get(); }
// присваивание пробрасывать или нет - определись сам. тут возможны варианты
reference& operator = (reference const& src) { get() = src.get(); return *this; }
// move-семантику - определись и продумай. тут возможны варианты
reference(reference&& src);
reference& operator = (reference&&);
T&& get()&&;
operator T&&()&&;
};
template<class T> struct pair
{
const char* key;
reference<T> value;
};
template<typename T>
struct pair {
const char *key; // никогда не изменяется, назначается только при инициализации 'pair'const T &val;
};
template<typename T>
void set(const pair<T> &pair) {
// тут все хорошо, используем 'pair.key' и 'pair.val'
}
template<typename T>
void get(pair<T> &pair) {
// тут все плохо, ибо 'pair.val' - константная ссылка
}
использовать это дело предполагается так:
pair<int> pi{"int", 33};
set(pair<int>{"int", 33});
set(pi);
////////////////////////////////
get(pi); // читаем в 'pair<int>'int rint=0;
get(pair<int>{"int", pint}); // читаем в 'pint' являющийся lvalue, 'pair<int>' же - rvalue
как победить?
спасибо.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Здравствуйте, niXman, Вы писали:
X>template<typename T> X>struct pair { X> const char *key; // никогда не изменяется, назначается только при инициализации 'pair' X> const T &val; X>};
странная структура, что ты планируешь делать (менять?) в функции get? в этой структуре можно менять указатель key. больше нечего
текущая проблема эта? http://ideone.com/t4lAzP
ps. ты бы лучше выкладывал полный код на ideone, проще было бы понимать что у тебя не так
Здравствуйте, niXman, Вы писали:
X>есть такой тип: X>
X>template<typename T>
X>struct pair {
X> const char *key; // никогда не изменяется, назначается только при инициализации 'pair'
X> const T &val;
X>};
X>
Почему никогда не изменяется? Ты не можешь изменить значение по указателю, а сам указатель — очень даже.
pair<int> p;
p.key = "test";
Чтобы не менялось нужно:
const char * const key;
И да, гет со ссылкой — странное решение, лучше возвращать.
Здравствуйте, niXman, Вы писали:
X>и так, с чего все исходит:
а если забить на пары?
template<typename Archive, typename... Args>
bool apply(Archive &ar, Args&&... args) {
// тут 'Args...' - пак пар в раскрытом виде
}
struct user_type {
int i;
long l;
float f;
// этот макрос генерит необходиммый код для сериализации/десериализации
YAS_SERIALIZE_ONE_MF(i, l, f);
// развернется он в нечто типа:template<typename Archive>
void serialize(Archive &ar) {
apply(
ar
, "i", i
, "l", l
, "f", f
);
}
};
Т.е. один тип аксессора на serialize/deserialize? А не проще пару было сделать const — не const?
Тогда бы честный был serialize(Archive &) const и deserialize(Archive&).
Re[3]: константа и не константа одновременно(почти)
Здравствуйте, sokel, Вы писали:
S>Здравствуйте, niXman, Вы писали:
S>Т.е. один тип аксессора на serialize/deserialize? А не проще пару было сделать const — не const? S>Тогда бы честный был serialize(Archive &) const и deserialize(Archive&).
Ещё вариант — собрать через шаблонны тип с метаданными, т.е. с аксессорами на каждое поле и дополнительными атрибутами для различных типов архива (вроде const char* key).
Ну а в apply уже бегать по метаданным, вытаскивая или заполняя члены через pointer-to-member.
Re[3]: константа и не константа одновременно(почти)
Здравствуйте, uzhas, Вы писали:
U>а если забить на пары?
кстати да, вариант... ща подумаю...
U>или убрать const из пары
неполучится, ибо у юзера должна быть возможность вписывать rvalue значения: https://ideone.com/t24wzm (строка 22)
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[3]: константа и не константа одновременно(почти)
Здравствуйте, sokel, Вы писали:
S>Т.е. один тип аксессора на serialize/deserialize? А не проще пару было сделать const — не const? S>Тогда бы честный был serialize(Archive &) const и deserialize(Archive&).
YAS поддерживает такие способы сериализации/десериализации:
yas::mem_ostream os;
yas::binary_oarchive<yas::mem_ostream> oa(os);
struct usertype {};
usertype u;
// 1: one free function for read/writetemplate<typename Archive>
void serialize(Archive &ar, usertype &v) {
ar & v;
}
// 2: separate free functionstemplate<typename Archive>
void serialize(Archive &ar, const usertype &v) { // write
ar & v;
}
template<typename Archive>
void serialize(Archive &ar, usertype &v) { // read
ar & v;
}
// 3: one member function for read/writestruct usertype2 {
int a, b;
template<typename Archive>
void serialize(Archive &ar) {
ar & a
& b;
}
};
// 4: separate member function for read/writestruct usertype3 {
int a, b;
template<typename Archive>
void serialize(Archive &ar) const { // write
ar & a
& b;
}
template<typename Archive>
void serialize(Archive &ar) { // read
ar & a
& b;
}
};
// ну и такое недавно добавил по просьбам пользователей:int a, b;
ar(a, b); // operator(...)
ar.serialize(a, b);
}
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Здравствуйте, niXman, Вы писали:
X>я тоже смотрел в эту сторону, а именно в сторону std::reference_wrapper,
Вот именно! reference_wrapper проблему не решает.
X>вроде то что надо...
А может, тебе надо не одну пару, а две — на передачу и на приём? Аналогично make_tuple и tie.
В чистом виде tie не подойдёт, поскольку первый компонент у тебя в любом случае значение, а tie даёт слишком много прав.
Но для прототипирования — почему бы и нет.
Перекуём баги на фичи!
Re[4]: константа и не константа одновременно(почти)
Здравствуйте, Кодт, Вы писали:
К>Вот именно! reference_wrapper проблему не решает.
может быть, я этот вариант долго не развивал... нарукоблудил свой.
К>А может, тебе надо не одну пару, а две — на передачу и на приём? Аналогично make_tuple и tie.
может быть...
а в чем смысл? что с моим решением не так?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[2]: константа и не константа одновременно(почти)
Здравствуйте, Кодт, Вы писали:
К>А может, тебе надо не одну пару, а две — на передачу и на приём?
пару оставил одну, а 'make_pair()' сделал две.
получилось еще проще:
#include <iostream>
/**************************************************************************/template<typename T>
void foo(T v) { std::cout << v.key << ": " << __PRETTY_FUNCTION__ << std::endl; }
template<typename T>
struct pair {
pair(T v)
:key("")
,val(v)
{}
pair(const char *k, T v)
:key(k)
,val(v)
{}
const char *key;
T val;
};
template<typename T>
auto make_pair(const char *key, T &val) {
return pair<T &>{key, val};
}
template<typename T>
auto make_pair(const char *key, const T &val) {
return pair<const T &>{key, val};
}
/**************************************************************************/struct type {
int a;
int b;
type()
:a{}
,b{}
{}
void m0() const {
const auto p0 = make_pair("type.a", a);
foo(p0);
}
void m1() {
const auto p0 = make_pair("type.b", b);
foo(p0);
}
};
/**************************************************************************/int main() {
type t;
t.m0();
t.m1();
int c=0;
const int d=0;
auto p0 = make_pair("b", 33);
foo(p0);
auto p1 = make_pair("c", c);
foo(p1);
auto p2 = make_pair("d", d);
foo(p2);
std::cout << "**********************************" << std::endl;
int f=0;
const int g=0;
foo(make_pair("i", 33));
foo(make_pair("f", f));
foo(make_pair("g", g));
}
/**************************************************************************/
Здравствуйте, niXman, Вы писали:
К>>А может, тебе надо не одну пару, а две — на передачу и на приём? Аналогично make_tuple и tie. X>может быть... X>а в чем смысл? что с моим решением не так?
Только то, что это велосипед. Там, где вполне можно было сериализовать пачки make_pair("xz", ref(this->xz)).
Кстати, константность накладывать-снимать прямо в паре — смысла нет, ведь serialize() и на чтение, и на запись не константна...
Но раз уж сделал, так сделал.
Перекуём баги на фичи!
Re[6]: константа и не константа одновременно(почти)
Здравствуйте, Кодт, Вы писали:
К>Кстати, константность накладывать-снимать прямо в паре — смысла нет, ведь serialize() и на чтение, и на запись не константна...
в этом случае — и константна и не константна:
struct type {
template<typename Ar>
void serialize(Ar &ar) const {} // save to arvoid serialize(Ar &ar) {} // read from ar
};
или я тебя не правильно понял?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Здравствуйте, niXman, Вы писали:
К>>Кстати, константность накладывать-снимать прямо в паре — смысла нет, ведь serialize() и на чтение, и на запись не константна... X>в этом случае — и константна и не константна: X>
X>struct type {
X> template<typename Ar>
X> void serialize(Ar &ar) const {} // save to ar
X> void serialize(Ar &ar) {} // read from ar
X>};
X>
X>или я тебя не правильно понял?
Что называется, ОЙ!
Но, с другой стороны, — если писать там tie в обоих перегрузках, то константность будет протащена бесплатно
template<class Ar, class Pair, class... Pairs>
void do_serialize_all(Ar& ar, Pair&& p, Pairs...&& ps)
{
do_serialize_one(ar, p);
do_serialize_all(ar, ps...);
}
template<class Arr, class T>
void do_serialize_one(Ar& ar, std::tuple<const char*, T&>&& p)
{
// поскольку одно из полей ссылочное, то распотрошить tuple, сопоставляя с tie, не получится.const char* key = std::get<0>(p);
T& var = std::get<1>(p);
??????? // сериализуй как хочешь
}
И вообще, чтобы два раза не писать содержание перегрузки, — хак константности
strust YourType
{
template<class Arr> void serialize(Ar& ar) const// можно только писать в архив
{
assert(serialize_mode_is_saving(ar));
const_cast<YourType*>(this)->serialize(ar); // внаглую снимем константность, - сейчас это нестрашно
}
template<class Arr> void serialize(Ar& ar) // может быть и туда, и сюда!
{
// всю содержательную работу сделаем в этой ветке
do_serialize_all(ar,
std::tie("x",x),
std::tie("y",y),
std::tie("z",z)
);
}
};
Перекуём баги на фичи!
Re[3]: константа и не константа одновременно(почти)
Здравствуйте, niXman, Вы писали:
К>>Что называется, ОЙ! X>поясни, плиз, что ты пытаешься сказать?
То, что я упустил этот момент
Что в твоём случае бывает сериализация константного объекта, и, как следствие, константность проникает внутрь пары.
Но, как уже сказал-показал, можно просто хакнуть константность и сериализовать всегда неконстантный объект. Хотя бы затем, чтобы два раза одинаковый код не писать.
Либо же придётся делать ещё один шаблон функции сериализации, параметризуемый ±константным типом твоей большой структуры.
Здравствуйте, Кодт, Вы писали:
К>То, что я упустил этот момент К>Что в твоём случае бывает сериализация константного объекта, и, как следствие, константность проникает внутрь пары.
ну да.
К>Но, как уже сказал-показал, можно просто хакнуть константность и сериализовать всегда неконстантный объект.
случаев, когда бы мне приходилось использовать отдельные сериализаторы/десериализаторы — в моей практике еще небыло. да и в чужих кодах я такого не встречал, правда.
да и константные объекты, так же, сериализовать не приходилось...
возможность юзеру реализовать отдельные сериализаторы/десериализаторы была добавлена мной исключительно ради "на всякий случай". один из таких примеров — условная сериализация/десериализация...
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[10]: константа и не константа одновременно(почти)