LINUX.ORG.RU

Предложение по стандарту C++

 , ,


0

3

Решил сделать свою библиотеку для работы с json. Существующие не нравятся тем, что обладают ужасным синтаксисом, так как не используют многие возможности из C++11 (например, std::initializer_list) Как известно, в json допускаются два вида коллекций данных - просто списки и ассоциативные контейнеры. Во многих языках, эти виды контейнеров декларативно описываются разным синтаксисом. В C++11 полявилась удобная штука, позволяющая задавать любые коллекции как {a, b, c}, что неявно преобразуется в std::initializer_list. Но для инициализации ассоциативного контейнера, к примеру, std::map, используется он же, наприимер {{key1, val1}, {key2, val2}}. Соответсвенно, при конструировании json объекта мы не можем отличить пришедший в конструктор std::initializer_list, описывающий ассоциативный контейнер от списка списков. Есть просто решение: выдумать отдельный синтаксис, который по аналогии с std::initializer_list и {a,b,c} будет преобразовываться в std::pair, например такой

{key: value}
, что должно раскрываться в
std::make_pair(key, value)
. По идее все логично, обратную совместимость ни с чем не нарушает, радикально переделывать компиляторы не придется. Почему не добавить такое в стандарт?



Последнее исправление: CatsCantFly (всего исправлений: 2)

Ответ на: комментарий от hateyoufeel

Потому что это удобно, и не сделать никак, не меняя сам язык. Сделали же {}. И в других языках такое есть.

CatsCantFly
() автор топика
Ответ на: комментарий от fluorite

Я же не json предлагаю добавлять в стандарт. И в этом примере та же проблема - не отличить список от пары ключ-значение.

CatsCantFly
() автор топика

если каждый будет рукоблудить свои «удобства» в стандарт, грош цена такому стандарту

anonymous
()
Ответ на: комментарий от anonymous

Чем отличается «рукоблудие каждого» от того, что туда уже добавили? initializer_list и range for тоже ничегокроме удобства не дают. Авторы C# и Python, которые добавили аналогичную конструкцию в эти языки - идиоты?

CatsCantFly
() автор топика

Вам бы всё лишь бы что-нибудь расширить

#include <map>
#include <string>
#include <iostream>
#include <sstream>

class JSON {
protected:
   std::map<std::string, std::string> fields;

public:
   JSON& operator() (const std::string &k, const std::string &v) {
      fields[k] = "\"" + v + "\"";
      return *this;
   }

   JSON& operator() (const std::string &k, const JSON &j) {
      fields[k] = j.str();
      return *this;
   }

   std::string str() const {
      std::stringstream ofs;
      auto it = fields.begin();
      ofs << "{ " << "\"" << it->first << "\" : " << it->second;
      ++it;
      for (; it != fields.end(); ++it) {
         ofs << ", \"" << it->first << "\" : " << it->second;
      }
      ofs << " }";
      return ofs.str();
   }
};

inline JSON j() {
   return JSON();
}

int main(int argc, char *argv[]) {
   JSON json = j()
      ("foo", "bar")
      ("LOR", "tort")
      ("nested", j()
       ("works", "fine")
       ("so",    "good"));

   std::cout << json.str() << std::endl;
   return 0;
}
$ ./a.out 
{ «LOR» : «tort», «foo» : «bar», «nested» : { «so» : «good», «works» : «fine» } }
yoghurt ★★★★★
()
Последнее исправление: yoghurt (всего исправлений: 1)
Ответ на: комментарий от staseg
auto root = jsonObject{jsonArray{{"key1", 1},
                       {"key2", 2},
                       {"key3", jsonArray{1, 2, 3}}}}

Тогда уж по этой логике. Если объект строится побольше и посложнее, количество jsonArray начнет превышать все пределы, вместо простого и лаконичного двоеточия.

CatsCantFly
() автор топика
Ответ на: комментарий от CatsCantFly

object это последовательность пар ключ-значение, array — последовательность значений. Так что не надо там ничего добавлять. Названия можно укоротить и запихнуть в нэймспейс, макросами можно вообще «красивые» сокращения сделать.

ЗЫ. Недавно на initializer list сделал DSL для парсера сообщений HL7 2.6, вообще норм вышло :)

staseg ★★★★★
()

Решил сделать свою библиотеку для работы с json.

Чем не устроили 100500 уже написанных библиотек?

Reset ★★★★★
()
Ответ на: комментарий от Reset

Написал же, они не исользуют современные фичи C++ типа списков инициализации, а то и вовсе на C, из-за чего имеют ужасный синтаксис. Хотя тут скинули более менее современную библиотеку, но о ней не знал. Самые популярные - ужас.

CatsCantFly
() автор топика
Ответ на: комментарий от CatsCantFly

Написал же, они не исользуют современные фичи C++ типа списков инициализации

Помимо упомянутой ранее header-only библиотеки есть ещё не такая переусложнённая библиотека от Dropbox.

quiet_readonly ★★★★
()

Нужно больше говна в стандарт! initialization_list-а недостаточно! Нужно больше!

Перегрузи какой-нибудь оператор, который тебе больше нравится и радуйся.

key << value
Kuzy ★★★
()

Не, не надо, спасибо. Тот же initializer_list и так гвоздями к std прибит, что вообще дикость. Подобного нам не надо.

mix_mix ★★★★★
()
Ответ на: комментарий от CatsCantFly

initializer_list и range for тоже ничегокроме удобства не дают.

Делают из uniform initialization syntax совсем не uniform.

Kuzy ★★★
()

Развиваем тему

Еще из хотелок по C++: более продвинутый автовывод типов. Как это точно формализовать, надо подумать. Пример:

std::vector<Very<Long, Useless::Template<Class>>> vect;
//...
std::copy(vect.cbegin(), vect.cend(), std::ostream_iterator<Very<Long, Useless::Template<Class>>>(stream));
Компилятор же знает, какой тип будут передавать ostream_iterator, но всё равно заставляет его писать. А хочется:
std::vector<Very<Long, Useless::Template<Class>>> vect;
//...
std::copy(vect.cbegin(), vect.cend(), std::ostream_iterator<auto>(stream));

CatsCantFly
() автор топика
Ответ на: комментарий от CatsCantFly

Сейчас возможно полное создание proxy-объекта, значит можно сделать и property самому. Осталось только определиться с требованиями.

А зачем они тебе?

anonymous
()
Ответ на: комментарий от Kuzy

Почему тебя смущает, что он имеет другой тип? Это более правильно, ведь проперти имеют атрибуты доступа и пр.

anonymous
()
Ответ на: комментарий от anonymous

Странный вопрос, потому что он это компилирует и располагает полной информацией о типах. И если ты в этом шаблоне поставишь что-то другое, выдаст ошибку.

CatsCantFly
() автор топика
Ответ на: комментарий от anonymous

Потому что, когда я пишу auto t = foo.p;, то меня не должно волновать что там, свойство или нет. В этом же суть пропертей, иначе они не нужны просто.

Еще нужно будет явное приведение писать при передачи в темплейтный аргумент.

Если случайно эту фигную куда-то как сырые данные отправить - вообще плохо будет.

Кстати, у get/set-методов этих проблем нет, хотя у них тоже атрибуты доступа и пр.

Kuzy ★★★
()
Последнее исправление: Kuzy (всего исправлений: 1)
Ответ на: комментарий от CatsCantFly

Можно функцию сделать на подобии make_unique. Для них вывод типов работает.

Kuzy ★★★
()
Ответ на: комментарий от Kuzy

С сайд эффектами тоже все неоднозначно будет.

Kuzy ★★★
()
Ответ на: комментарий от Kuzy

А еще с приведением типов - не получится сделать приведение к ссылке на тип, иначе теряются все get/set.

void f(int& arg);
//...
f(t.foo); //никак не получится

CatsCantFly
() автор топика
Ответ на: комментарий от CatsCantFly

Там ведь внутри вызов функции. Если явно написать ее типом int&, то все будет работать. Иначе это rvalue и все правильно. В гипотетических пропертях на уровне языка так же должно быть.

Kuzy ★★★
()
Ответ на: комментарий от Kuzy

Так в том и дело, что у методов доступ внешний. А проперти само имеет разные доступы: как минимум для чтения и для записи.

Потому что, когда я пишу auto t = foo.p;, то меня не должно волновать что там, свойство или нет.

А почему тебя это волнует? Ну будет там не int, а property<int, ...>, который, когда нужно, кастанется в int...

Зато можно писать:

auto t = foo.p;
...
t = ...; // меняем foo.p

anonymous
()
Ответ на: комментарий от CatsCantFly

Так и не должно быть. Даже если ты в язык проперти протащишь. Ведь если ты определил get/set, то вызывать нужно их, а не обычную запись в память. Откуда кампилятору при компиляции f об этом знать?

anonymous
()
Ответ на: комментарий от anonymous

Это не проперти. Они не решают проблему с кучей get/set-функций.

Зато можно писать:

Я не спорю, это может понадобится, но это вообще не замена get/set-функциям.

Если их использовать как в твоем примере, то нужно вообще запретить неявное приведение, что бы случайно не скопировать эту фигню и менять именно foo.p и получать нужные сайд-эффекты от приведение к базовому типу. Но это совсем не проперти.

Это у тебя что-то вроде эмуляции ссылок на темплейтах, с опциональными функциями на «разыменовании» и присвоении.

Kuzy ★★★
()
Последнее исправление: Kuzy (всего исправлений: 1)
Ответ на: комментарий от Kuzy

Это не проперти. Они не решают проблему с кучей get/set-функций.

Вполне решают. Можно более реальный пример, где они не работают?

И вполне себе проперти, почему нет?

anonymous
()

потому что нефиг поощрять смешение данных с кодом, это плохой стиль

C++

ой, простите, что это я. всё хорошо, одобряю

MyTrooName ★★★★★
()
Ответ на: комментарий от anonymous
template <typename T>
void foo(T t) {
  // код для всех типов
}

template <>
void foo(bool t) {
  // код для bool
}

// ...

struct Obj {
  bool getV() const;
  Get<Obj, bool, &Obj::getV> v;
} obj;

bool Obj::getV() {
  std::cout << "getV!" << std::endl; // тут может быть кеширование, запись в лог, много чего может быть.
  return true;
}

// ...

foo(obj.getV()); // get - вызов второй функции
foo(obj.v); // property - вызов первой функции

// ...

auto a = obj.getV(); // вызов getV
if(p1(a) && p(a)) { /* .. */ }

auto b = obj.v; // getV не вызван
if(p1(b) && p(b)) { /* .. */ } // getV вызван два раза! Ленивость!

Не заменяет get/set, вообщем.

А за неявное приведение вообще убивать.

Kuzy ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.