константа и не константа одновременно(почти)
От: niXman Ниоткуда https://github.com/niXman
Дата: 08.05.15 07:17
Оценка:
привет!

есть такой тип:
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 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Отредактировано 08.05.2015 7:27 niXman . Предыдущая версия .
Re: константа и не константа одновременно(почти)
От: sokel Россия  
Дата: 08.05.15 08:20
Оценка:
Здравствуйте, niXman, Вы писали:

X>как победить?


template<typename T>
pair<T> get()
Re: константа и не константа одновременно(почти)
От: uzhas Ниоткуда  
Дата: 08.05.15 08:21
Оценка:
Здравствуйте, 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, проще было бы понимать что у тебя не так
Re: константа и не константа одновременно(почти)
От: Nikе Россия  
Дата: 08.05.15 08:23
Оценка:
Здравствуйте, 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;

И да, гет со ссылкой — странное решение, лучше возвращать.
Нужно разобрать угил.
Re: константа и не константа одновременно(почти)
От: niXman Ниоткуда https://github.com/niXman
Дата: 08.05.15 08:49
Оценка:
и так, с чего все исходит:
есть такая функция:
template<typename Archive, typename... Args>
bool apply(Archive &ar, Args&&... args) {
   // тут 'Args...' - пак пар
   // тут в/из 'ar' записывается/считывается '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
         ,pair<decltype(i)>{"i", i}
         ,pair<decltype(l)>{"l", l}
         ,pair<decltype(f)>{"f", f}
      );
   }
};
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Отредактировано 08.05.2015 8:50 niXman . Предыдущая версия . Еще …
Отредактировано 08.05.2015 8:49 niXman . Предыдущая версия .
Re: константа и не константа одновременно(почти)
От: Кодт Россия  
Дата: 08.05.15 08:49
Оценка: 9 (1) +1
Здравствуйте, niXman, Вы писали:

Тебе нужна глубокая, а не поверхностная константность. С аналогичной проблемой столкнёшься, если будешь вместо голой ссылки или использовать указатели (голые, умные, 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;
};
Перекуём баги на фичи!
Re[2]: константа и не константа одновременно(почти)
От: niXman Ниоткуда https://github.com/niXman
Дата: 08.05.15 08:58
Оценка:
Здравствуйте, Кодт, Вы писали:

я тоже смотрел в эту сторону, а именно в сторону std::reference_wrapper, но в итоге сделал так:
#include <iostream>
#include <type_traits>

template<typename T>
void foo(T) { std::cout << __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) {
        using R = typename std::conditional<
             std::is_rvalue_reference<decltype(val)>::value || std::is_const<decltype(val)>::value
            ,const T&
            ,T&
        >::type;
    return pair<R>{key, val};
}

int main() {
    int i=0;
    auto p0 = make_pair("i", 33);
    foo(p0);
    auto p1 = make_pair("i", i);
    foo(p1);

    foo(make_pair("i", 33));
    foo(make_pair("i", i));
}

https://ideone.com/jWmnKj

вроде то что надо...
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[2]: константа и не константа одновременно(почти)
От: uzhas Ниоткуда  
Дата: 08.05.15 09:07
Оценка:
Здравствуйте, 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
      );
   }
};


или убрать const из пары: http://ideone.com/Y1p2RK
Re[2]: константа и не константа одновременно(почти)
От: sokel Россия  
Дата: 08.05.15 09:24
Оценка:
Здравствуйте, niXman, Вы писали:

Т.е. один тип аксессора на serialize/deserialize? А не проще пару было сделать const — не const?
Тогда бы честный был serialize(Archive &) const и deserialize(Archive&).
Re[3]: константа и не константа одновременно(почти)
От: sokel Россия  
Дата: 08.05.15 09:37
Оценка:
Здравствуйте, sokel, Вы писали:

S>Здравствуйте, niXman, Вы писали:


S>Т.е. один тип аксессора на serialize/deserialize? А не проще пару было сделать const — не const?

S>Тогда бы честный был serialize(Archive &) const и deserialize(Archive&).

Ещё вариант — собрать через шаблонны тип с метаданными, т.е. с аксессорами на каждое поле и дополнительными атрибутами для различных типов архива (вроде const char* key).
Ну а в apply уже бегать по метаданным, вытаскивая или заполняя члены через pointer-to-member.
Re[3]: константа и не константа одновременно(почти)
От: niXman Ниоткуда https://github.com/niXman
Дата: 08.05.15 09:59
Оценка:
Здравствуйте, uzhas, Вы писали:

U>а если забить на пары?

кстати да, вариант... ща подумаю...

U>или убрать const из пары

неполучится, ибо у юзера должна быть возможность вписывать rvalue значения:
https://ideone.com/t24wzm (строка 22)
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[3]: константа и не константа одновременно(почти)
От: niXman Ниоткуда https://github.com/niXman
Дата: 08.05.15 10:09
Оценка:
Здравствуйте, 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/write
template<typename Archive>
void serialize(Archive &ar, usertype &v) {
   ar & v;
}

// 2: separate free functions
template<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/write
struct usertype2 {
   int a, b;

   template<typename Archive>
   void serialize(Archive &ar) {
      ar & a
         & b;
   }
};


// 4: separate member function for read/write
struct 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 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Отредактировано 08.05.2015 10:37 niXman . Предыдущая версия . Еще …
Отредактировано 08.05.2015 10:11 niXman . Предыдущая версия .
Re[3]: константа и не константа одновременно(почти)
От: Кодт Россия  
Дата: 08.05.15 10:42
Оценка:
Здравствуйте, niXman, Вы писали:

X>я тоже смотрел в эту сторону, а именно в сторону std::reference_wrapper,

Вот именно! reference_wrapper проблему не решает.

X>вроде то что надо...

А может, тебе надо не одну пару, а две — на передачу и на приём? Аналогично make_tuple и tie.

В чистом виде tie не подойдёт, поскольку первый компонент у тебя в любом случае значение, а tie даёт слишком много прав.
Но для прототипирования — почему бы и нет.
Перекуём баги на фичи!
Re[4]: константа и не константа одновременно(почти)
От: niXman Ниоткуда https://github.com/niXman
Дата: 08.05.15 10:49
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Вот именно! reference_wrapper проблему не решает.

может быть, я этот вариант долго не развивал... нарукоблудил свой.

К>А может, тебе надо не одну пару, а две — на передачу и на приём? Аналогично make_tuple и tie.

может быть...
а в чем смысл? что с моим решением не так?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[2]: константа и не константа одновременно(почти)
От: niXman Ниоткуда https://github.com/niXman
Дата: 08.05.15 11:07
Оценка:
Здравствуйте, Nikе, Вы писали:

N>Почему никогда не изменяется?

потому что не нужно.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[4]: константа и не константа одновременно(почти)
От: niXman Ниоткуда https://github.com/niXman
Дата: 08.05.15 11:38
Оценка:
Здравствуйте, Кодт, Вы писали:

К>А может, тебе надо не одну пару, а две — на передачу и на приём?

пару оставил одну, а '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));
}

/**************************************************************************/


https://ideone.com/6vr1Oh
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[5]: константа и не константа одновременно(почти)
От: Кодт Россия  
Дата: 08.05.15 11:50
Оценка:
Здравствуйте, niXman, Вы писали:

К>>А может, тебе надо не одну пару, а две — на передачу и на приём? Аналогично make_tuple и tie.

X>может быть...
X>а в чем смысл? что с моим решением не так?

Только то, что это велосипед. Там, где вполне можно было сериализовать пачки make_pair("xz", ref(this->xz)).
Кстати, константность накладывать-снимать прямо в паре — смысла нет, ведь serialize() и на чтение, и на запись не константна...

Но раз уж сделал, так сделал.
Перекуём баги на фичи!
Re[6]: константа и не константа одновременно(почти)
От: niXman Ниоткуда https://github.com/niXman
Дата: 08.05.15 12:27
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Кстати, константность накладывать-снимать прямо в паре — смысла нет, ведь serialize() и на чтение, и на запись не константна...

в этом случае — и константна и не константна:
struct type {
   template<typename Ar>
   void serialize(Ar &ar) const {} // save to ar
   void serialize(Ar &ar) {} // read from ar
};

или я тебя не правильно понял?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Отредактировано 08.05.2015 13:32 niXman . Предыдущая версия .
Re[7]: константа и не константа одновременно(почти)
От: Кодт Россия  
Дата: 08.05.15 14:29
Оценка:
Здравствуйте, 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]: константа и не константа одновременно(почти)
От: Nikе Россия  
Дата: 08.05.15 14:44
Оценка:
Здравствуйте, niXman, Вы писали:

N>>Почему никогда не изменяется?

X>потому что не нужно.

Я к тому, что при данной форме записи оно меняется. Кстати, это вопрос на собеседовании, что значат:
const T* t;
T const* t;
T* const t;
Нужно разобрать угил.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.