Синтаксический сахар в C / C ++ - PullRequest
31 голосов
/ 09 апреля 2011

Я искал Ruby и нашел его ключевые слова "пока" и "если" очень интересным. Поэтому я подумал, что было бы хорошим способом добавить похожие ключевые слова в C / C ++. Вот что я придумал:

#define until(x)    while(!(x))
#define unless(x)   if(!(x))

Я ищу несколько предложений по этому вопросу. Кто-нибудь может предложить лучшую альтернативу?

Вот пример программы, которую я написал, чтобы проиллюстрировать, что я намеревался сделать:

#include <stdio.h>
#include <stdlib.h>

#define until(x)    while(!(x))
#define unless(x)   if(!(x))

unsigned int factorial(unsigned int n) {
    unsigned int fact=1, i;
    until ( n==0 )
        fact *= n--;
    return fact;    
}

int main(int argc, char*argv[]) {
    unless (argc==2)
        puts("Usage: fact <num>");
    else {
        int n = atoi(argv[1]);
        if (n<0)
            puts("please give +ve number");
        else
            printf("factorial(%u) = %u\n",n,factorial(n));
    }
    return 0;
}

Было бы замечательно, если бы вы указали мне некоторые ссылки на похожие приемы, которые можно использовать в C или C ++.

Ответы [ 10 ]

109 голосов
/ 09 апреля 2011

Кто-нибудь может предложить лучшую альтернативу?

Да. Не делай этого вообще. Просто используйте операторы while и if напрямую.

Когда вы программируете на C или C ++, программируйте на C или C ++. Хотя until и unless могут использоваться часто и идиоматично в некоторых языках, их нет в C или C ++.

16 голосов
/ 12 апреля 2011

То, как вы это сделали, мне кажется правильным способом сделать это, если вы вообще собираетесь это делать.Поскольку расширение макроса , поэтому похоже на то, что вы ожидаете [1], я думаю, что допустимо, чтобы макрос выглядел как синтаксис (), а не как обычно рекомендуемый SCARY_UPPERCASE_MACROS (), который используетсячтобы показать, что этот код не соответствует обычному синтаксису, и вы должны использовать его только осторожно.

[1] Единственным недостатком является невозможность объявления переменных, что маловероятно в любом случае и может привести к ошибке вправильное место при неправильном использовании, вместо того, чтобы делать что-то странное.

Более того, важно даже небольшое увеличение читабельности, поэтому возможность сказать until ( вместо while (! действительно облегчает чтение многихпетли.Если конечное условие легче воспринимать как исключительное условие (независимо от того, есть оно или нет), запись цикла таким образом облегчает чтение.Так что, хотя это всего лишь синтаксический сахар, я думаю, что есть причина для его рассмотрения.

Однако Не думаю, что оно того стоит.Преимущество невелико, так как большинство программистов привыкли читать if (!, а стоимость реальна: любой, кто читает код, должен проверить, является ли это макрос или пользовательский компилятор, и выполняет ли он то, что думает.И это может ввести в заблуждение, заставляя вас думать, что вы можете делать такие вещи, как i=5 unless xxxx;.Такие небольшие улучшения, если они будут широко распространены, будут фрагментировать язык, поэтому часто лучше делать все стандартным образом и применять улучшения медленно.

Однако, это можно сделать хорошо: полный набор надстроек и tr1, особенноРабота с шаблонами, которая выглядит как расширение библиотеки, включает в себя расширение C ++ различными способами, многие из которых не приняты, поскольку они не кажутся оправданными, но многие из них имеют небольшое или очень широкое распространение, потому что онисделаны реальные улучшения.

13 голосов
/ 09 апреля 2011

Это напомнило мне кое-что, что я видел в чьем-то коде:

#define R return;

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

8 голосов
/ 09 апреля 2011

Я полагаю, что лучше их не использовать.

Вы не можете использовать их в стиле Ruby, поскольку

`printf("hello,world") unless(a>0);`

недопустимо.

И это будетпрограммистам на C трудно понять код.Между тем, дополнительный макрос может быть проблемой.

5 голосов
/ 10 апреля 2011

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

until (T* p = f(x)) ...
unless (T* p = f(x)) ...

с другой стороны, мы можем написать как:

while (T* p = f(x)) ...
if (T* p = f(x)) ...

Что касается unless, если мы определим его как:

#define unless(x) if (x) {} else

тогда мы можем написать unless (T* p = f(x)) .... Однако в этом случае мы не можем добавьте else предложение после него.

5 голосов
/ 09 апреля 2011

Если вы собираетесь определять макросы, то хорошо, чтобы они выглядели очень некрасиво.В частности, они должны быть прописными и иметь какой-то префикс.Это связано с тем, что нет пространства имен и нет координации с системой типов или разрешением перегрузки C ++.

Так что если бы ваш макрос назывался BIGYAN_UNNECESSARY_MACRO_UNTIL, то он был бы не совсем "за пределами".

Если вы хотите расширить C ++ новыми циклическими конструкциями, рассмотрите возможность исследования лямбда-выражений в C ++ 0x, где вы можете разрешить:

until([&] { return finished; }, [&] 
{
    // do stuff
});

Это не идеально, но лучше, чем макросы.

2 голосов
/ 22 августа 2012

Пример синтаксического сахара (ИМХО):

struct Foo {
    void bar() {}
};
typedef std::vector<Foo*> FooVector;
typedef boost::ptr_vector<Foo> FooPtrVector;

FooVector v1;
for (FooVector::iterator it = v1.begin(); it != v1.end(); ++it)
    (*it)->bar(); // ugly

FooPtrVector v2;
for (FooPtrVector::iterator it = v2.begin(); it != v2.end(); ++it)
    it->bar(); // nice
2 голосов
/ 10 апреля 2011

Посмотрите, как происходит повышение foreach.

Заголовок определяет BOOST_FOREACH (некрасивый макрос с префиксом). Вы можете

#define foreach BOOST_FOREACH

в ваших .cpp файлах, чтобы иметь более чистый код. Вы не должны делать это в своих .h файлах и использовать вместо этого уродливый BOOST_FOREACH.

Теперь вот набор макросов «функционального программирования» для «удобных» выражений IF THEN ELSE (потому что?: Некрасиво):

#define IF(x) (x) ?
#define ELSE :

сейчас

int x = IF(y==0) 1
        ELSE IF(y<0) 2*y
        ELSE 3*y;

десугаризуется в:

int x = (y==0) ? 1 : (y<0) ? 2*y : 3*y;
1 голос
/ 22 июля 2013

Как говорили люди, добавление этих слов на самом деле не дает полезного синтаксического сахара, потому что стоимость чтения некоторое время (или if (! Мала), к которой привыкли все разработчики на C, и использование такого макроса вас пугаетБольшинство разработчиков на C. Кроме того, не очень хорошая идея сделать язык похожим на другой.

НО, синтаксический сахар имеет значение. Как уже говорилось, в C ++, boost добавляет много синтаксического сахара через шаблоны,и stl также предоставляет сахар Somme (например, std::make_pair(a, b) является синтаксическим сахаром для std::pair<decltype(a), decltype(b)>(a, b).

. По мере улучшения языка добавляются как функциональные возможности, так и синтаксический сахар, чтобы улучшить читаемость, удобочитаемость и эффективностьразработчики. Например, в спецификации C ++ 11 было добавлено «for (элементы в структуре данных)» (см. ниже), а также ключевое слово «auto», которое допускает недельный вывод типов (я говорю слабый, потому что вам нужнонабирать много типов во многих местах, где тип на самом деле является «очевидным» и избыточным).

Также в haskell, используя монады безнотация do (синтаксический сахар) была бы настоящей болью, и никто бы не использовал их 1 .


Пример без синтаксического сахара:

//C++ < 11
std::vector<int> v;
v.push_back(3);
v.push_back(7);
v.push_back(9);
v.push_back(12);
for (std::vector<int>::iterator it = v.begin();
     it != v.end();
     it++)
{
    std::cout << *it << std::endl;
}

И с синтаксическим сахаром:

//C++ >= 11
std::vector<int> v {3, 7, 9, 12};

for (auto elm : v)
{
    std::cout << elm << std::endl;
}

Чуть более читабельно, нет?


Пример haskell для монады ввода / вывода (из HaskellWiki ):

f :: IO String
f =
  ask "What's your name ?" >>= \name ->
  putStrLn "Write something." >>= \_ ->
  getLine >>= \string ->
  putStrLn ("Hello " ++ name ++ " you wrote " ++ string) >>= \_ ->
  return name

g :: IO String    
g = do
  name <- ask "What's your name ?"
  putStrLn "Write something."
  string <- getLine
  putStrLn ("Hello " ++ name ++ " you wrote " ++ string)
  return name

Вот ссылка на ideone: http://ideone.com/v9BqiZ


1 : На самом деле язык более гибкий, чем C ++, и позволяет создавать операторы(например, & ^, +.,: + :, ...), поэтому мы можем представить, что кто-то снова быстро введет синтаксический сахар:).

0 голосов
/ 01 октября 2018

Хорошо, вы можете это сделать, но убедитесь, что его нет в исходном файле.Я рекомендую использовать подход CoffeeScript к JavaScript без генерации оптимизации.

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

Попробуйте заглянуть в awk и заставить его переносить все файлы с окончанием .cugar при сохранении или чем-то подобным.:)

Удачи.

...