Внутренние функции, имеющие дело с переменными из области видимости - PullRequest
5 голосов
/ 02 января 2012

У меня есть фрагмент кода, подобный следующему:

std::list<boost::shared_ptr<Point> > left, right;
// ... fill lists ...

// now, calculate the angle between (right[0], right[1]) and (right[0], left[0])
double alpha = angle(*(right.begin()->get()), *(((++right.begin()))->get()), *(left.begin()->get()) );

std::cout << alpha * 180 / M_PI << std::endl;

if(alpha < 0){
    // do something with the lists, like reversing them. Especially the beginning and end of the lists may change in some way, but "left" and "right" are not reassigned.
}

// calculate the new alpha
alpha = angle(*(right.begin()->get()), *(((++right.begin()))->get()), *(left.begin()->get()) );

Помимо магии приращения итератора, которая может быть не слишком очевидной без комментариев, я бы хотел определить функцию double alpha() дляуменьшить дублирование.Но поскольку использование этой функции очень специфично, я бы хотел сделать ее локальной.В идеале так:

int a, b;
int sum(){ return a + b; }
a = 5; b = 6;
int s = sum(); // s = 11
a = 3;
s = sum(); // s = 9 now

В таких языках, как Python, это было бы совершенно нормально, но как это сделать в C ++?

РЕДАКТИРОВАТЬ:

Это то, что я закончилВ завершение, отдельное спасибо @wilx и флагу компилятора -std=c++0x:

auto alpha = [&right, &left]() {

    // not 100% correct due to my usage of boost::shared_ptr, but to get the idea

    Point r_first = *(right.begin()); 
    Point l_first = *(left.begin());
    Point r_second = *(++right.begin());

    return angle(r_first, r_second, l_first);
};


if(alpha() < 0) // fix it

double new_alpha = alpha();

Ответы [ 3 ]

2 голосов
/ 02 января 2012

C ++ не поддерживает вложенные функции, но обходной путь можно сделать с помощью классов в области функций:

void scopeFnc()
{
  struct Inner
  {
     static int nestedFnc() { return 5; }
  };

  int a = Inner::nestedFnc();
}
1 голос
/ 02 января 2012

В этом случае я бы предложил использовать перегрузку типа angle2(std::list<Point> const &, etc.). Два простых аргумента лучше, чем у вас сейчас.

С C ++ 11 вы можете использовать лямбда-выражения, которые отлавливают свои аргументы по ссылке.

Если вы не можете использовать C ++ 11 и чувствуете себя авантюрным, попробуйте Boost.Phoenix (часть Boost.Spirit).

0 голосов
/ 02 января 2012

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

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

int a, b;
#define SUM() (a+b)
int s=sum()
#undef SUM
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...