Синтаксический сахар в C / C++

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

#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) = %un",n,factorial(n));
    }
    return 0;
}

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

10 ответов


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

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

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

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

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


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

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

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


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

#define R return;

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


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

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

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

является незаконным.

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


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

Итак, если ваш был вызван макрос BIGYAN_UNNECESSARY_MACRO_UNTIL тогда это было бы не совсем "за гранью".

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

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

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


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


пример хорошего синтаксиса сахара (IMHO):

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

посмотрите, как выполняется boost foreach.

заголовок определяет BOOST_FOREACH (уродливый макрос с префиксом). Ты можешь!--5-->

#define foreach BOOST_FOREACH

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

теперь, вот набор макросов "функционального программирования" для "удобного", если тогда еще выражения (потому что ?: есть ugly):

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

теперь

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

desugarises в:

int x = (y==0) ? 1 : (y<0) ? 2*y : 3*y;

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

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

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

также, в haskell использование монад без обозначения (синтаксического сахара) было бы настоящей болью, и никто не использовал бы их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 для монады IO (от 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++, и позволяет создавать операторы (например,&^,+., :+:, ...), поэтому мы могли представить, что кто-то быстро введет синтаксический сахар снова :).


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

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

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

удачи.