Как я могу переписать этот код JavaScript для C ++ 11? - PullRequest
3 голосов
/ 31 января 2012

Это код закрытия javascript, который я видел в полном руководстве по Javascript.Я хотел бы написать это как C ++ 11

var uniqueID1 = (function()
{
    var id = 0;
    return function() { return id++; };
})();    

Это код cpp, который я написал.Но это не скомпилировано.Может ли C ++ 11 представлять одно и то же выражение?

auto c = []() -> int (*)() { int x = 0; return [&x]() -> int { return x++; }};

Я использую VS2010

Редактировать: Это полный пример кода JavaScript, который я сделал.Вы можете легко проверить, как работает код в вашем веб-браузере.

<head>
<script language="javascript">
var uniqueID1 = (function()
{
    var id = 0;
    return function() { return id++; };
})();

var uniqueID2 = (function()
{
      var id = 0;
      return function() { return id++; };
})();
</script>
</head>

<body>
        <input value = "uniqueid1" type="button" OnClick="alert(uniqueID1());"></input>
        <input value = "uniqueid2" type="button" OnClick="alert(uniqueID2());"></input>
</body>
</html>

Ответы [ 2 ]

19 голосов
/ 31 января 2012

Хорошо, сначала давайте разберем, что делает ваш JavaScript.

function()
{
    var id = 0;
    return function() { return id++; };
}

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

Каждый раз, когда эта функция вызывается, она возвращает new функция.Эта новая функция будет иметь свое собственное состояние (в конце концов, var id = 0; должен что-то делать).Каждый вызов внешней функции будет возвращать новую функцию с новым состоянием.

This:

(function()
{
    var id = 0;
    return function() { return id++; };
})

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

(function()
{
    var id = 0;
    return function() { return id++; };
})()

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

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

Учитывая все это, мы можем видеть, что это утверждение:

var uniqueID1 = (function()
{
    var id = 0;
    return function() { return id++; };
})();

Создаетвнешняя функция вызывает функцию, которая возвращает новую функцию, а затем сохраняет функцию inner в переменной с именем uniqueID1.

Если вам нужно доказать, что это правда, попробуйте этов вашем HTML:

var uniqueMaker = function()
{
    var id = 0;
    return function() { return id++; };
};

var uniqueID1 = uniqueMaker();
var uniqueID2 = uniqueMaker();

Вы получите тот же ответ, что и в вашей версии для копирования и вставки.

Если мы хотим, чтобы код C ++ имитировал это, нам нужно выполнить каждый шагс правильным кодом C ++.

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

int id = 0;
return [=]() mutable { return ++id; };

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

[]() -> std::function<int()>
{
  int x = 0;
  return [=]() mutable { return x++; };
}

Это создает лямбда-функцию, которая при вызове возвращает внутреннюю функцию со своим собственным состоянием.Состояние, которое не зависит от любых последующих вызовов этой функции.Как в примере с JavaScript.

Теперь этого недостаточно.Помните, ваш JavaScript создает внешнюю функцию, вызывает ее и сохраняет only ее возвращаемое значение.Сама внешняя функция отбрасывается.Таким образом, мы должны подражать этому.К счастью, это достаточно просто в C ++;он выглядит так же, как JavaScript:

([]() -> std::function<int()>
{
  int x = 0;
  return [=]() mutable { return x++; };
})()

Наконец, мы помещаем его в переменную:

auto uniqueID1 = ([]() -> std::function<int()>
{
  int x = 0;
  return [=]() mutable { return x++; };
})();

Тип uniqueID1 будет std::function<int()>.Это не будет тип внешней функции.Внешняя функция - это просто временная функция, которая использовалась для создания внутренней области видимости.

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

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

class UniqueID
{
    unsigned int value;
public:
    UniqueID() : value(0) { }
    unsigned int operator()() { return ++value; }
};

Использование:

UniqueID gen1, gen2;

some_function(gen1());
another_function(gen2());
Foo x(Blue, "Jim", gen1());

Этот подход легче, чем обертка std::function, хотя прямая лямбда создаст похожую структуру данных (хотя вы не можете знать ее имя типа). Вы можете инициализировать value в -1, если хотите, чтобы первый идентификатор был 0 (хотя может быть полезно зарезервировать 0 в качестве специального значения).

...