Использование std :: tr1 :: bind с std :: vector :: push_back - PullRequest
2 голосов
/ 15 мая 2011

Почему мой VS2010 не может скомпилировать этот код:

#include <functional>
#include <vector>
int main()
{
    std::vector<int> vec;
    std::bind(&std::vector<int>::push_back, std::ref(vec), 1)();
    return 0;
}

Ответы [ 4 ]

5 голосов
/ 15 мая 2011

Вы должны быть более конкретным, почему это не работает для вас.

#include <iostream>
#include <tr1/functional>
#include <vector>

int main(int argc, char* argv[]) {
    std::vector<int> vec;
    std::tr1::bind(&std::vector<int>::push_back, std::tr1::ref(vec), 1)();
    std::cout << "vec.size = " << vec.size() << std::endl;
    std::cout << "vec[0] = " << vec[0] << std::endl;
    return 0;
}

$ gcc -o test -lstdc++ test.cpp && ./test
vec.size = 1
vec[0] = 1

Обновление: Люк Дантон прав, проблема здесь в перегрузке push_back. См. Вопрос Существуют ли проблемы boost :: bind с VS2010? . Также обратите внимание, что проблема не ограничена push_back, см. Visual Studio 2010 и boost :: bind .

4 голосов
/ 15 мая 2011

Суть в том, что то, что вы пытаетесь сделать, невозможно в portable C ++. std::vector<>::push_back гарантированно будет перегружено в компиляторах C ++ 11, поскольку как минимум должна быть перегрузка для lvalues ​​и перегрузка для rvalues.

Обычно , принимая адрес перегруженной функции-члена, §13.4 / 1 в FDIS C ++ 11 говорит нам, что мы можем контролировать, какую перегрузку мы получаем адрес, таким образом:

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

  • инициализируемый объект или ссылка,
  • левая сторона задания,
  • параметр функции,
  • параметр пользовательского оператора,
  • возвращаемое значение функции, операторской функции или преобразования,
  • явное преобразование типа или
  • нетипизированный шаблон-параметр.

Перед именем перегруженной функции может стоять оператор &. Перегруженное имя функции не должно использоваться без аргументов в контекстах, отличных от перечисленных. [ Примечание: Любой избыточный набор скобок, окружающих имя перегруженной функции, игнорируется. - Конечная заметка ]

Проблема исходит из §17.6.5.5 / 2:

Реализация может объявлять дополнительные не виртуальные сигнатуры функций-членов в классе, добавляя аргументы со значениями по умолчанию к сигнатуре функции-члена; следовательно, адрес функции-члена класса в стандартной библиотеке C ++ имеет неопределенный тип.

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

Предложенный Люком Дантоном обходной путь (в частности, с использованием лямбды) также является тем, что я бы порекомендовал:

std::vector<int> vec;
[&](){ vec.push_back(1); }();
3 голосов
/ 15 мая 2011

Попробуйте это:

struct push_back {
    void
    operator()(std::vector<int>& vector, int i) const
    {
        vector.push_back(i);
    }
};

// somewhere else:
std::vector<int> vec;
std::tr1::bind(push_back(), std::tr1::ref(vec), 1)();

В C ++ 03 обратите внимание, что push_back не может быть локальным типом; с C ++ 11 можно, но было бы более идиоматичным (и полностью эквивалентным) использовать лямбду.

По всей вероятности, ваша реализация обеспечивает перегрузки для std::vector<T>::push_back, и поэтому ее адрес должен быть неоднозначным. Если это то, что произошло, ваш компилятор должен был предоставить вам соответствующее сообщение об ошибке. В всех случаях вы должны объяснить, что вы подразумеваете под «это невозможно».


Смысл не использовать такого помощника функции. - пурпурный

Тогда почему вы не поставили это в вопросе? Я не могу читать твои мысли.

Вы также можете попробовать это:

std::vector<int> vec;
void (std::vector<int>::*push_back)(int const&) = &std::vector<int>::push_back;
std::tr1::bind(push_back(), std::tr1::ref(vec), 1)();

Что, я считаю, не гарантирует успеха.

0 голосов
/ 15 мая 2011

Это должно выглядеть примерно так:

std::vector<int> vec;
std::tr1::bind(&std::vector<int>::push_back, std::tr1::ref(vec), _1)(1);
...