Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

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

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

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

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

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

Ответ 2

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

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

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

Ответ 3

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

#define R return;

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

Ответ 4

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

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

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

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

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

Ответ 5

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

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

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

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

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

Ответ 6

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

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 после него.

Ответ 7

Хороший пример синтаксического сахара (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

Ответ 8

Посмотрите, как выполняется форсирование 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;

desugarises в:

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

Ответ 9

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

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

По мере совершенствования языка добавляются как функциональные возможности, так и синтаксический сахар для повышения удобочитаемости, возможности записи и эффективности разработчиков. Например, с помощью спецификации С++ 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 your name ?" >>= \name ->
  putStrLn "Write something." >>= \_ ->
  getLine >>= \string ->
  putStrLn ("Hello " ++ name ++ " you wrote " ++ string) >>= \_ ->
  return name

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

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


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