Какие новые возможности добавляют в C ++ определяемые пользователем литералы?


140

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(как plain ints), а только потом 06_AD(не говоря уже о том, что август и сентябрь должны быть написаны без 0восьмеричных чисел). Это можно обойти, сделав синтаксис 1974-1/6_ADтаким, чтобы порядок оценки оператора работал, но он был неуклюжим.

Итак, мой вопрос сводится к следующему: считаете ли вы, что эта функция себя оправдает? Какие еще литералы вы хотите определить, чтобы сделать ваш код на C ++ более читабельным?


Обновлен синтаксис для соответствия окончательному проекту от июня 2011 г.


78
@DeadMG, если у вас есть проблема с заголовком, вы можете его отредактировать. Немного забавно пытаться закрыть вопрос трехлетней давности, в котором 11 положительных голосов и 8 избранных. (Не говоря уже о том, что этикет на этом сайте изменился за последние 3 года).
Motti

6
Думаю, у вас в примерах ошибка: string operator "" _s(const char*s);"нельзя использовать для синтаксического анализа "hello"_s". Это строковый литерал, который будет искать оператор с дополнительным size_tпараметром. Я прав?
Towi

@towi, ты прав. Я обновлю вопрос (я думаю, что это изменение стандарта с момента написания вопроса, но я не уверен).
Мотти

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 01

Ответы:


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, принимающему строку (по крайней мере, без аргументов строкового шаблона).


8
Вы можете сделать то же самое, предоставив std :: bitset правильный конструктор constexpr.
Никол Болас

1
@NicolBolas Ты прав. Я действительно удивлен, что никого там нет. Может быть, нам стоит предложить одну или две на 2014 год, если еще не поздно.
emsr

193

На первый взгляд, это простой синтаксический сахар.

Но если заглянуть глубже, мы увидим, что это больше, чем синтаксический сахар, поскольку он расширяет возможности пользователя C ++ для создания пользовательских типов, которые ведут себя точно так же, как отдельные встроенные типы. В этом небольшом «бонусе» является очень интересное дополнение C ++ 11 к C ++.

А действительно ли это нужно в C ++?

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

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

В C ++ у нас была возможность создавать наши собственные типы (то есть классы), потенциально без накладных расходов (встраивание и т. Д.). У нас была возможность добавлять операторы к их типам, чтобы они вели себя как похожие встроенные типы, что позволяет разработчикам C ++ использовать матрицы и комплексные числа так же естественно, как если бы они были добавлены в сам язык. Мы даже можем добавить операторы приведения (обычно это плохая идея, но иногда это просто правильное решение).

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

Итак, я полагаю, что это естественная эволюция языка, но должна быть как можно более полной: « Если вы хотите создать тип, и вы хотите, чтобы он вел себя как можно больше как встроенные типы, вот инструменты. .. "

Я предполагаю, что это очень похоже на решение .NET сделать каждый примитив структурой, включая логические, целые числа и т. Д., И унаследовать все структуры от Object. Одно только это решение выводит .NET далеко за пределы возможностей Java при работе с примитивами, независимо от того, сколько хаков для упаковки / распаковки Java добавит в свою спецификацию.

ВАМ это действительно нужно на C ++?

На этот вопрос ВЫ должны ответить. Только не Бьярн Страуструп. Только не Херб Саттер. Ни один член комитета по стандартизации C ++. Вот почему у вас есть выбор в C ++ , и они не ограничивают полезную нотацию только встроенными типами.

Если вам это нужно, то это долгожданное дополнение. Если нет, что ж ... Не используйте это. Это вам ничего не будет стоить.

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

Вздутие ??? Покажи мне свои комплексы !!!

Есть разница между раздутым и сложным (каламбур).

Как показано Нильсом на сайте Какие новые возможности пользовательские литералы добавляют в 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, и тип «std :: complex» в C ++ можно умножать, складывать, вычитать и т. Д. С помощью перегрузки оператора.

Но в C99 они просто добавили еще один тип как встроенный тип и встроенную поддержку перегрузки операторов. И они добавили еще одну встроенную буквальную функцию.

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

В C, если вам нужно такое же улучшение обозначений для другого типа, вам не повезет, пока вы не начнете лоббировать добавление ваших квантовых волновых функций (или трехмерных точек, или любого другого базового типа, который вы используете в своей области работы) в Стандарт 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

Это очень хорошо для математического кода. Я совершенно не понимаю, как можно использовать следующие операторы:

deg для градусов. Это делает запись абсолютных углов намного более интуитивной.

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

@masterxilo Конечно, на самом деле ваш пример абсурден: UDL не сложнее выучить, чем функции, как синтаксический сахар для них - и, кроме того, любая хорошая библиотека использует только те функции, которые необходимы для улучшения UX - и точно документирует то, что она все средства. Если кто-то злоупотребляет функцией для генерации нечитаемого кода (при условии, что этого вообще можно избежать в его работе ...), это не делает эту функцию виноватой, а только ее использование. Кроме того, нечитабельность для одного человека - хлеб с маслом для другого. Это все мнения и варианты . Если они вам не нравятся, не волнуйтесь! Вам не обязательно их использовать. Другие могут .
underscore_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

Бьярн Страуструп рассказывает о UDL в своем выступлении на C ++ 11 , в первом разделе, посвященном интерфейсам с множеством типов, примерно через 20 минут.

Его основной аргумент в пользу UDL принимает форму силлогизма:

  1. «Тривиальные» типы, т. Е. Встроенные примитивные типы, могут обнаруживать только тривиальные ошибки типов. Интерфейсы с расширенными типами позволяют системе типов улавливать больше видов ошибок.

  2. Типы ошибок типов, которые может обнаружить богато типизированный код, влияют на реальный код. (Он приводит пример Mars Climate Orbiter, который, как известно, вышел из строя из-за ошибки размеров в важной константе).

  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 без зависимостей от Nic Holthaus .
Martin Moene

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 ++ требуют ввода в радианах. Я думаю, что в градусах, поэтому очень короткое неявное преобразование, подобное опубликованному Nils, очень приятно.

В конечном счете, это будет синтаксический сахар, но это окажет небольшое влияние на читаемость. И, вероятно, будет проще написать некоторые выражения (sin (180.0deg) легче написать, чем sin (deg (180.0)). И тогда найдутся люди, которые злоупотребляют этой концепцией. Но тогда люди, злоупотребляющие языком, должны использовать очень ограничительные языки, а не такие выразительные, как C ++.

Ах, в моем посте в основном ничего не говорится, кроме: все будет хорошо, влияние не будет слишком большим. Не волнуйтесь. :-)


5
Ваши скобки неуравновешены! Извините, мой ОКР тоже меня ненавидит.
X-Istence

3

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


2

C ++ обычно очень строго относится к используемому синтаксису - за исключением препроцессора, мало что можно использовать для определения пользовательского синтаксиса / грамматики. Например, мы можем перегрузить существующие операции, но мы не можем определить новые - ИМО, это очень созвучно духу C ++.

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

Даже предполагаемое использование может значительно затруднить чтение исходного кода: одна буква может иметь обширные побочные эффекты, которые никак нельзя идентифицировать из контекста. При симметрии u, l и f большинство разработчиков выберут отдельные буквы.

Это также может превратить определение объема в проблему, использование отдельных букв в глобальном пространстве имен, вероятно, будет считаться плохой практикой, а инструменты, которые, как предполагается, упрощают смешивание библиотек (пространства имен и описательные идентификаторы), вероятно, не справятся с его назначением.

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

Однако мне интересно, какие умные идеи мы придумываем.


1
using single letters in global namespace will probably be considered bad practiceНо это не имеет отношения: (A) UDL должны быть определены в области (неглобального) пространства имен ... предположительно потому, что (B) они должны состоять из символа подчеркивания, затем> = 1 буквы, а не только буквы, и таких идентификаторов в глобальные NS зарезервированы для реализации. Это как минимум 2 балла против идеи, что UDL изначально порождают путаницу. Что касается необходимости ограничивать пространство имен, уменьшая полезность функции, поэтому, например, stdlib объявляет их в inline namespaces, которые пользователи могут импортировать оптом при желании.
underscore_d

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

Ключевое слово «авто» может быть оправдано, но только возможно. Но возьмем только C ++, потому что в этом аспекте он лучше, чем C ++ 0x.

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

Это как .. так просто. Даже если подумать, что все стандартные и острые скобки просто неуместны, если вы используете их повсюду. Я не начинаю гадать, какой синтаксис есть в 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: «Линейный шум в этой штуке огромен». Нет, это не ... «И читать ужасно». Ваш субъективный аргумент интересен, но вам следует взглянуть на перегрузку операторов в целом, чтобы увидеть, что код для этой функции далеко не
удивит

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

1
@kts: С C ++ 1x у нас будет лямбда и диапазон для
Джо Д.

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