Які нові можливості додають визначені користувачем літерали до C ++?


139

C ++ 11 представляє визначені користувачем літерали , які дозволять введення нового буквального синтаксису на основі існуючих литералов ( int, hex, string, float) , так що будь-який тип буде мати можливість буквального уявлення.

Приклади:

// imaginary numbers
std::complex<long double> operator "" _i(long double d) // cooked form
{ 
    return std::complex<long double>(0, d); 
}
auto val = 3.14_i; // val = complex<long double>(0, 3.14)

// binary values
int operator "" _B(const char*); // raw form
int answer = 101010_B; // answer = 42

// std::string
std::string operator "" _s(const char* str, size_t /*length*/) 
{ 
    return std::string(str); 
}

auto hi = "hello"_s + " world"; // + works, "hello"_s is a string not a pointer

// units
assert(1_kg == 2.2_lb); // give or take 0.00462262 pounds

На перший погляд це виглядає дуже круто, але мені цікаво, наскільки це насправді застосовано, коли я намагався думати про наявність суфіксів _ADта _BCстворення дат, я виявив, що це проблематично через замовлення оператора. 1974/01/06_ADспочатку оцінювали б 1974/01(як звичайні int), а лише пізніше06_AD (нічого не сказати про серпень та вересень, що потрібно писати без 0восьми причин). Це можна вирішити, якщо синтаксис буде 1974-1/6_ADтаким, щоб замовлення оператора працювало, але воно було незграбним.

Тож, на чому зводиться моє запитання, це, чи вважаєте ви, що ця особливість виправдає себе? Які ще літерали ви хочете визначити, що зробить ваш код C ++ більш читабельним?


Оновлений синтаксис, щоб відповідати остаточному проекту червня 2011 року


8
Я буду голосувати, щоб закрити це. Назва досить явно запальна.
Щеня

76
@DeadMG, якщо у вас є проблема з заголовком, ви можете відредагувати його. Смішно намагатися закрити 3-річне запитання, яке містить 11 результатів та 8 фаворитів. (Не кажучи вже про те, що етикет на цьому сайті змінився за останні 3 роки).
Мотті

5
Я думаю, у вас є помилка у ваших прикладах: string operator "" _s(const char*s);"не можна використовувати для розбору "hello"_s". Це рядковий літерал і буде шукати оператора з додатковим size_tпараметром. Маю рацію?
букси

1
Мене цікавило одне - чи має сенс писати "портативний C" на C ++, замінюючи такі типи, uint16_tчия поведінка залежить від реалізації, подібними типами uwrap16та unum16поведінка яких не залежатиме від реалізації, такими, що враховують uwrap16 w=1; unum16 n=1;вирази w-2та n-2дасть (uwrap16)65535і (int)-1відповідно [ uint16_tдасть перший результат у системах, де int16 біт, а другий у системах, де intбільший]. Найбільша проблема, яку я бачив, - це поводження з цифровими буквами.
supercat

1
Можливість безперебійної взаємодії числових літералів з іншими числовими типами з визначеною поведінкою виглядає так, що це повинно дозволяти використовувати такі типи для створення мови, де код, який хотів виконувати дії, залежні від впровадження, могли це робити, не покладаючись на виконання, визначена поведінка. Є кілька місць, де IDB як і раніше буде неминучим, оскільки такі речі, як різниці покажчиків і sizeofповертають цілі типи, залежні від реалізації, але ситуацію все-таки можна зробити набагато кращою, ніж вона є. Що б ви думали про цю концепцію?
supercat

Відповіді:


71

Ось випадок, коли є перевага використовувати визначені користувачем літерали замість виклику конструктора:

#include <bitset>
#include <iostream>

template<char... Bits>
  struct checkbits
  {
    static const bool valid = false;
  };

template<char High, char... Bits>
  struct checkbits<High, Bits...>
  {
    static const bool valid = (High == '0' || High == '1')
                   && checkbits<Bits...>::valid;
  };

template<char High>
  struct checkbits<High>
  {
    static const bool valid = (High == '0' || High == '1');
  };

template<char... Bits>
  inline constexpr std::bitset<sizeof...(Bits)>
  operator"" _bits() noexcept
  {
    static_assert(checkbits<Bits...>::valid, "invalid digit in binary string");
    return std::bitset<sizeof...(Bits)>((char []){Bits..., '\0'});
  }

int
main()
{
  auto bits = 0101010101010101010101010101010101010101010101010101010101010101_bits;
  std::cout << bits << std::endl;
  std::cout << "size = " << bits.size() << std::endl;
  std::cout << "count = " << bits.count() << std::endl;
  std::cout << "value = " << bits.to_ullong() << std::endl;

  //  This triggers the static_assert at compile time.
  auto badbits = 2101010101010101010101010101010101010101010101010101010101010101_bits;

  //  This throws at run time.
  std::bitset<64> badbits2("2101010101010101010101010101010101010101010101010101010101010101_bits");
}

Перевага полягає в тому, що виняток під час запуску перетворюється на помилку часу компіляції. Ви не можете додати статичне твердження до бітового ctor, приймаючи рядок (принаймні, не без аргументів шаблону рядків).


7
Можна зробити те ж саме, надавши std :: bitset належному конструктору constexpr.
Нікол Болас

1
@NicolBolas Ви маєте рацію. Я насправді здивований, що його немає там. Можливо, ми повинні запропонувати один-два на 2014 рік, якщо це не пізно.
emsr

192

На перший погляд, це здається простим синтаксичним цукром.

Але, дивлячись глибше, ми бачимо, що це більше, ніж синтаксичний цукор, оскільки він розширює можливості користувача C ++ для створення визначених користувачем типів, які ведуть себе так само, як різні вбудовані типи. У цьому цей маленький «бонус» є дуже цікавим доповненням C ++ 11 до C ++.

Чи справді нам це потрібно в C ++?

Я бачу кілька застосувань у коді, про який писав у минулі роки, але те, що я не використовував його на C ++, не означає, що це не цікаво іншому розробнику C ++ .

Ми використовували в C ++ (і, напевно, у C), визначеному компілятором літерали, для введення цілих чисел як коротких чи довгих цілих чисел, дійсних чисел як плаваючі чи подвійні (або навіть довгі подвійні), а символьні рядки як звичайні чи широкі символи .

У C ++ у нас була можливість створювати власні типи (тобто класи), які потенційно не мають накладних витрат (вбудовування тощо). У нас була можливість додати операторів до їх типів, щоб вони поводилися як подібні вбудовані типи, що дозволяє розробникам C ++ використовувати матриці та складні числа так само природно, як це було б, якби вони були додані до самої мови. Ми навіть можемо додати операторів лиття (що зазвичай погана ідея, але іноді це лише правильне рішення).

Ми все ще пропустили одне, щоб типи користувачів поводилися як вбудовані типи: визначені користувачем літерали.

Отже, я думаю, це природна еволюція для мови, але бути максимально повною: " Якщо ви хочете створити тип, і ви хочете, щоб він максимум поводився як вбудовані типи, ось інструменти. .. "

Я думаю, це дуже схоже на рішення .NET зробити кожен примітив структурою, включаючи булеві числа, цілі числа тощо, і всі структури походять від Object. Саме таке рішення дозволяє .NET далеко виходити за межі Java під час роботи з примітивами, незалежно від того, скільки хакерських та розблокуючих хакерів Java додасть до своєї специфікації.

Вам справді це потрібно в C ++?

Це питання для ВАС відповіді. Не Bjarne Stroustrup. Не Трава Саттер. Не будь-яким членом стандартного комітету C ++. Ось чому у вас є вибір у C ++ , і вони не обмежуватимуть корисні позначення лише вбудованими типами.

Якщо вам це потрібно, то це вітальне доповнення. Якщо ви цього не зробите, ну ... Не використовуйте. Це вам нічого не коштуватиме.

Ласкаво просимо до C ++, мови, де функції необов’язкові.

Здутий ??? Покажіть мені свої комплекси !!!

Існує різниця між роздутим і складним (призначений для каламбура).

Як показано Niels at Які нові можливості додають визначені користувачем літерали до C ++? , вміння записати складне число - одна з двох функцій, доданих "нещодавно" до C та C ++:

// C89:
MyComplex z1 = { 1, 2 } ;

// C99: You'll note I is a macro, which can lead
// to very interesting situations...
double complex z1 = 1 + 2*I;

// C++:
std::complex<double> z1(1, 2) ;

// C++11: You'll note that "i" won't ever bother
// you elsewhere
std::complex<double> z1 = 1 + 2_i ;

Тепер і C99 тип "подвійний комплекс", і тип C ++ "std :: complex" можна множити, додавати, віднімати тощо, використовуючи перевантаження оператора.

Але в C99 вони просто додали інший тип як вбудований тип, так і вбудовану підтримку перевантаження операторів. І вони додали ще одну вбудовану буквальну функцію.

В C ++ вони просто використовували існуючі функції мови, бачили, що буквальна особливість - це природна еволюція мови, і таким чином її додавали.

У C, якщо вам потрібне таке ж покращення позначень для іншого типу, вам не пощастить, поки ваше лобіювання не додасть ваші квантові хвильові функції (або 3D-точки, або будь-який базовий тип, який ви використовуєте у своїй галузі роботи) Стандарт C як вбудований тип вдається.

У C ++ 11 ви просто можете це зробити самостійно:

Point p = 25_x + 13_y + 3_z ; // 3D point

Він роздутий? Ні , в цьому є потреба, як показано тим, як і комплексам C, і C ++ потрібен спосіб представити свої буквальні комплексні значення.

Це неправильно розроблено? Ні , він розроблений як і всі інші функції C ++, маючи на увазі розширення.

Це лише для позначення? Ні , оскільки це може навіть додати безпеку типу до вашого коду.

Наприклад, уявимо код, орієнтований на CSS:

css::Font::Size p0 = 12_pt ;       // Ok
css::Font::Size p1 = 50_percent ;  // Ok
css::Font::Size p2 = 15_px ;       // Ok
css::Font::Size p3 = 10_em ;       // Ok
css::Font::Size p4 = 15 ;         // ERROR : Won't compile !

Тоді дуже легко застосувати сильне введення присвоєння значень.

Чи небезпечно?

Гарне питання. Чи можна використовувати ці функції в просторі імен? Якщо так, то джекпот!

У будь-якому випадку, як і все, ви можете вбити себе, якщо інструмент використаний неправильно . C є потужним, і ви можете відстріляти голову, якщо неправомірно використовувати C гармати. У C ++ є пістолет C, а також скальпель, тазер і будь-який інший інструмент, який ви знайдете в наборі інструментів. Можна зловживати скальпелем і знебарвити себе до смерті. Або ви можете створити дуже елегантний та надійний код.

Отже, як і кожна функція C ++, вона вам справді потрібна? Це питання, на яке ви повинні відповісти, перш ніж використовувати його в C ++. Якщо ви цього не зробите, це нічого не обійдеться. Але якщо вам це справді потрібно, принаймні, мова не підведе вас.

Приклад дати?

Мені здається, помилка в тому, що ви змішуєте операторів:

1974/01/06AD
    ^  ^  ^

Цього не уникнути, оскільки / будучи оператором, компілятор повинен його інтерпретувати. І, AFAIK, це добре.

Щоб знайти рішення вашої проблеми, я би написав буквальне якось іншим способом. Наприклад:

"1974-01-06"_AD ;   // ISO-like notation
"06/01/1974"_AD ;   // french-date-like notation
"jan 06 1974"_AD ;  // US-date-like notation
19740106_AD ;       // integer-date-like notation

Особисто я вибрав би цілі числа та дати ISO, але це залежить від ВАШИХ потреб. У чому полягає суть дозволу користувачеві визначати власні буквальні імена.


1
Дякую, я та інші мої альтернативні особистості були виявлені. Більш серйозно, я писав це поодинці, але, можливо, я використовую вираз рідної мови, і вони не перекладаються добре англійською.
paercebal

Щодо "різних частин", як показують їх назви, вибачте, я думаю, що це організує дещо досить довгий пост. Що стосується жирного тексту, то це підсумок абзацу, в якому вони перебувають. Люди, які бажають лише інформації без обґрунтування, можуть обмежити їх читання на заголовках та жирному тексті.
paercebal

3
+1. Дійсно приємне пояснення. Ми чекаємо, коли це буде здійснено. Для нас це дійсно важливо. Ми працюємо над MDE (Model-Driven Engineering) і вважаємо це необхідністю. Я додаю відповідь нижче, щоб пояснити наш випадок.
Дієго Севілья

9
@TGV: you can write 1+2i, but you still can't write a+bi, so there's absolutely no pointНавіть ігнорувати ваш a+biприклад смішно, те, що ви сприймаєте його як "низьку частоту", не означає, що всі це роблять. . . Дивлячись на велику картину, справа полягає в тому, щоб переконатися, що визначені користувачем об’єкти можна максимально вважати першокласними громадянами мови, наскільки це вбудовані типи. Отже, якщо ти вмієш писати 1.5fі 1000ULчому б ти не зміг написати 25iчи навіть 100101b? На відміну від C та Java, типи користувачів не повинні вважатися громадянами другого класу мови на C ++.
paercebal

3
@Anton:: Most of data still comes from IOУ коді дуже багато твердо кодованих значень. Подивіться на всі булі, усі цілі числа, всі подвійні елементи, що входять до коду, тому що зручніше писати x = 2 * y ;замість того, x = Two * yде Twoє сильно набрана константа. Зазначені користувачем літерали дозволяють нам поставити на нього тип і записати: x = 2_speed * y ;і дозволити компілятору перевірити, чи обчислення має сенс. . . Все стосується сильного набору тексту. . . Можливо, ви не скористаєтесь цим. Але я впевнений, що, як тільки я зможу використовувати компілятор з підтримкою C ++ 11 на роботі.
paercebal

36

Це дуже приємно для математичного коду. Я не можу побачити використання для таких операторів:

град. для градусів. Це робить абсолютні кути набагато інтуїтивнішими.

double operator ""_deg(long double d)
{ 
    // returns radians
    return d*M_PI/180; 
}

Він також може бути використаний для різних зображень з фіксованою точкою (які все ще використовуються в області DSP та графіки).

int operator ""_fix(long double d)
{ 
    // returns d as a 1.15.16 fixed point number
    return (int)(d*65536.0f); 
}

Вони виглядають як приємні приклади, як це використовувати. Вони допомагають зробити константи в коді більш читабельними. Це ще один інструмент, щоб зробити код нечитабельним, але ми вже маємо стільки зловживань інструментами, що ще один не сильно шкодить.


1
"але ми вже маємо стільки зловживань інструментами, що ще один не сильно шкодить. Нічого, я сподіваюся, що це не філософія, що стоїть за всім, що c ++ [x] 1234567890 затоплює останнім часом. Уявіть, що вам доведеться вивчити бібліотеку, яка використовує всі ці, плюс десять форматів файлів для конфігурації та два інструменти для попередньої та
післяобробної

@masterxilo Звичайно, насправді ваш приклад є абсурдним: UDL не є складнішим для вивчення, ніж функціям, як просто синтаксичний цукор для них. всі засоби. Якщо хтось зловживає функцією для генерування нечитабельного коду (якщо припустити, що це взагалі можна уникнути у своїй роботі ...), ця функція не винна, а лише використання. Плюс, одна людина нечитабельна - це хліб з маслом іншого. Це все думки - & варіанти . Якщо вони вам не подобаються, не хвилюйтесь! Не потрібно їх використовувати. Інші можуть .
підкреслюйте_d

17

UDL розміщуються в просторі імен (їх можна імпортувати за допомогою декларацій / директив, але ви не можете явно простору імен у буквальному сенсі 3.14std::i ), це означає, що там (сподіваємось) не буде тони сутичок.

Те, що вони насправді можуть бути шаблонованими (і constexpr'd), означає, що ви можете робити досить потужні речі з UDL. Автори Bigint будуть дуже щасливі, оскільки вони, нарешті, можуть мати довільно великі константи, обчислені під час компіляції (через constexpr або шаблони).

Мені просто сумно, що ми не побачимо пару корисних літералів у стандарті (як виглядає), як sдля std::stringтаi для уявної одиниці.

Кількість часу кодування, який буде збережено UDL, насправді не така велика, але читабельність буде значно збільшуватися, і все більше і більше обчислень може бути переведено на час збирання для швидшого виконання.


Дякую, що вияснили питання про простори імен ... Мені це було цікаво.
Натан Рід

12

Дозвольте додати трохи контексту. Для нашої роботи дуже потрібні визначені користувачем літерали. Ми працюємо над MDE (Model-Driven Engineering). Ми хочемо визначити моделі та метамоделі в C ++. Ми фактично реалізували відображення від Ecore до C ++ ( EMF4CPP) ).

Проблема виникає, коли можна визначити елементи моделі як класи в C ++. Ми застосовуємо підхід перетворення метамоделі (Ecore) в шаблони з аргументами. Аргументи шаблону - це структурна характеристика типів та класів. Наприклад, клас з двома атрибутами int буде чимось на зразок:

typedef ::ecore::Class< Attribute<int>, Attribute<int> > MyClass;

Хоча, виявляється, що кожен елемент моделі чи метамоделі, як правило, має ім’я. Ми хотіли б написати:

typedef ::ecore::Class< "MyClass", Attribute< "x", int>, Attribute<"y", int> > MyClass;

АЛЕ, C ++, ні C ++ 0x цього не дозволяють, оскільки рядки заборонені як аргументи шаблонів. Ви можете написати ім'я char за допомогою char, але це безперечно безлад. З належними визначеними користувачем літералами ми могли б написати щось подібне. Скажімо, ми використовуємо "_n" для ідентифікації назв елементів моделі (я не використовую точний синтаксис, просто для створення ідеї):

typedef ::ecore::Class< MyClass_n, Attribute< x_n, int>, Attribute<y_n, int> > MyClass;

Нарешті, використання цих визначень як шаблонів дуже допомагає нам розробити алгоритми для переходу елементів моделі, перетворень моделі тощо, які є дійсно ефективними, оскільки інформація про тип, ідентифікація, перетворення тощо визначається компілятором під час компіляції.


4
Мені дуже подобається ця by the compiler at compile timeчастина ... :-)
paercebal

12

Bjarne Stroustrup розповідає про UDL в цій розмові C ++ 11 , у першому розділі про інтерфейси, багаті на типи, приблизно через 20 хвилин.

Його основний аргумент для UDL має форму силогізму:

  1. "Тривіальні" типи, тобто вбудовані примітивні типи, можуть вловлювати лише помилки тривіального типу. Інтерфейси з більш багатими типами дозволяють системі типів вловлювати більше видів помилок.

  2. Види помилок типу, які може набути рясно набраний код, впливають на реальний код. (Він наводить приклад Марса кліматичного орбітера, який ганебно вийшов з ладу через помилку розмірів у важливій постійній).

  3. У реальному коді одиниці використовуються рідко. Люди не використовують їх, тому що запускати обчислення часу виконання або пам'ять на обсяг пам'яті для створення багатих типів занадто дорого, а використання попередньо існуючого C ++ шаблонного одиничного коду настільки потворно, що ніхто не використовує його. (Емпірично це ніхто не використовує, хоча бібліотеки існують вже десятиліття).

  4. Тому, щоб змусити інженерів використовувати одиниці в реальному коді, нам знадобився пристрій, який (1) не вимагає накладних витрат на виконання та (2) умовно прийнятний.


9

Підтримка перевірки виміру часу компіляції - єдине необхідне обґрунтування.

auto force = 2_N; 
auto dx = 2_m; 
auto energy = force * dx; 

assert(energy == 4_J); 

Дивіться, наприклад, PhysUnits-CT-Cpp11 , невелику бібліотеку C ++ 11, C ++ 14, призначену лише для заголовка, розмірний аналіз часу та маніпулювання одиницею / кількістю та перетворення. Простіше, ніж Boost.Units , чи підтримують літеральні символи одиниці, такі як m, g, s, метричні префікси, такі як m, k, M, залежить лише від стандартної бібліотеки C ++, лише для SI, від цілісних потужностей розмірів.


Або перегляньте одиниці , час компіляції, лише заголовок, розмірний аналіз та бібліотеку перетворення одиниць, побудовану на c ++ 14 без залежностей від Ніка Гольфа .
Мартін Моен

6

Хм ... Я ще не думав про цю особливість. Ваш зразок був добре продуманий і, безумовно, цікавий. C ++ дуже потужний, як зараз, але, на жаль, синтаксис, який використовується у прочитаних фрагментах коду, часом надто складний. Читання - якщо не все, то принаймні багато. І така особливість була б спрямована на більшу читабельність. Якщо я візьму ваш останній приклад

assert(1_kg == 2.2_lb); // give or take 0.00462262 pounds

... Цікаво, як би ти це висловив сьогодні. У вас буде клас KG та LB і ви порівнювали б неявні об’єкти:

assert(KG(1.0f) == LB(2.2f));

І це теж би зробити. З типами, які мають довші імена або типи, для яких ви не сподіваєтесь мати такий приємний конструктор для запису адаптера, це може бути приємним доповненням для створення та ініціалізації об'єктивних об'єктів на ходу. З іншого боку, ви вже можете створювати та ініціалізувати об'єкти, використовуючи методи.

Але я погоджуюсь з Нілсом з математики. Наприклад, функції тригонометрії C і C ++ вимагають введення в радіанах. Я думаю, що в градусах, тому дуже коротке неявне перетворення, як розміщений Нілс, дуже приємне.

Зрештою, це буде синтаксичний цукор, але це матиме незначний вплив на читабельність. І, ймовірно, буде простіше писати і деякі вирази (гріх (180,0 дег) простіше писати, ніж гріх (град (180,0)). І тоді знайдуться люди, які зловживають цим поняттям. Але тоді люди, які зловживають мовою, повинні використовувати дуже обмежувальні мови, а не щось таке виразне, як C ++.

Ах, в моєму повідомленні в основному немає нічого, крім: це буде добре, вплив не буде надто великим. Не будемо хвилюватися. :-)


5
Ваші дужки незбалансовані! Вибачте, мій OCD мене теж ненавидить.
X-Istence

3

Я ніколи не потребував і не хотів цієї функції (але це може бути ефект Blub ). Моя реакція на ривок коліна полягає в тому, що це кульгаво, і, ймовірно, сподобається тим самим людям, які вважають, що це здорово перевантажувати оператора + для будь-якої операції, яка віддалено може розглядатися як додавання.


Я підтверджую: Дуже цікава стаття.
paercebal

2

C ++, як правило, дуже суворий щодо використовуваного синтаксису - заборона препроцесора існує не так багато, яку ви можете використовувати для визначення спеціального синтаксису / граматики. Наприклад, ми можемо перевантажувати існуючі опери, але не можемо визначити нові - IMO, це дуже співзвучно духу C ++.

Я не заперечую проти деяких способів для більш налаштованого вихідного коду - але обрана точка мені здається дуже ізольованою, що мене найбільше бентежить.

Навіть призначене використання може значно ускладнити читання вихідного коду: одна літера може мати величезні побічні ефекти, які жодним чином не можна визначити з контексту. З симетрією до u, l і f, більшість розробників вибирають одні літери.

Це також може перетворити пробірку в проблему, використання однієї літери в глобальному просторі імен, ймовірно, буде вважатися поганою практикою, а інструменти, які передбачають легше змішування бібліотек (простори імен та описові ідентифікатори), ймовірно, переможуть її призначення.

Я бачу певні заслуги в поєднанні з "авто", також у поєднанні з бібліотекою одиниць , як підсилюючі одиниці , але недостатньо, щоб заслужити це завдання.

Цікаво, однак, які розумні ідеї ми придумуємо.


1
using single letters in global namespace will probably be considered bad practiceАле це не має ніякого значення: (A) UDL повинні бути визначені в (не глобальній) області простору імен ... імовірно, тому що (B) вони повинні складатися з підкреслення, тоді> = 1 буква, а не лише літера, і такі ідентифікатори в глобальна НС зарезервована для реалізації. Це, принаймні, 2 бали проти ідеї, що UDL вмить створюють плутанину. Що стосується необхідності застосування простору імен, зменшуючи корисність функції, саме тому, наприклад, stdlib оголошує їх у inline namespaces, що користувачі можуть імпортувати оптом за бажанням.
підкреслити_

2

Я використовував літеральні дані для бінарних рядків на зразок цього:

 "asd\0\0\0\1"_b

використовуючи std::string(str, n)конструктор, так що\0 не розрізати рядок навпіл. (Проект робить багато роботи з різними форматами файлів.)

Це було корисним і тоді, коли я відступив std::stringна користь обгортки для std::vector.


-5

Шум лінії в цій речі величезний. Також жахливо читати.

Дозвольте мені знати, чи вони спричинили це додавання нового синтаксису з будь-якими прикладами? Наприклад, чи є у них кілька програм, які вже використовують C ++ 0x?

Для мене ця частина:

auto val = 3.14_i

Не виправдовує цю частину:

std::complex<double> operator ""_i(long double d) // cooked form
{ 
    return std::complex(0, d);
}

Навіть якщо ви не використовуєте i-синтаксис і в 1000 інших рядках. Якщо ви пишете, ви, ймовірно, також пишете 10000 рядків чогось іншого. Особливо, коли ви все ще напевно пишете в основному всюди це:

std::complex<double> val = 3.14i

'auto' -keyword може бути виправданим, хоча, тільки можливо. Але давайте візьмемо лише C ++, оскільки в цьому аспекті це краще, ніж C ++ 0x.

std::complex<double> val = std::complex(0, 3.14);

Це як… все просто. Навіть подумав, що всі STD і точні дужки просто кульгають, якщо ти їх використовуєш скрізь. Я не починаю здогадуватися, який синтаксис є у C ++ 0x для перетворення std :: complex під складний.

complex = std::complex<double>;

Це, можливо, щось прямо, але я не вірю, що це так просто в C ++ 0x.

typedef std::complex<double> complex;

complex val = std::complex(0, 3.14);

Можливо? > :)

У будь-якому разі, справа в тому: писати 3.14i замість std :: complex (0, 3.14); не заощаджує багато часу в цілому, за винятком кількох супер особливих випадків.


10
@Cheery: Для вас "auto val = 3.14i" не виправдовує код, написаний для його підтримки. Я можу відповісти, що для мене "printf ("% i ", 25)" не виправдовує код, написаний для printf. Ви бачите візерунок?
paercebal

5
@Cheery: "Шум у цій справі величезний". Ні, це не ... "Також це жахливо читати". Ваш суб'єктивний аргумент цікавий, але вам слід поглянути на перевантаження оператора взагалі, щоб побачити код для цієї функції - це далеко не дивно / шокуюче ... Для розробника C ++
paercebal

3
Авто допоможе читати. Подумайте про використання інтераторів у циклі for: for (auto it = vec.begin (); it! = vec.end (); ++ it) ... Я знаю про for_each, але не любить створювати функтор, щоб використовувати його .
KitsuneYMG

1
@kts: З C ++ 1x у нас з'явиться лямбда і діапазон для
Jo D

3
Якщо ваша лінія C ++ краща, ніж C ++ 0x, то моя лінія ще краща. Написати просто: std::complex<double> val(0, 3.14);.
Бен Войгт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.