Указатель переменной-члена

Для данной структуры:

struct foo
{
    void fooFunc(){}
    int fooVar = 0;
};

Я могу создать оболочку вызова для функции: std::mem_fn( &foo::fooFunc ), чтобы я мог передать ее другому методу и вызвать ее для объекта.
Я хочу знать, существует ли аналогичная оболочка вызова, но для переменных-членов.

Например, здесь я использую указатель на переменную-член, но я хотел бы использовать оболочку вызова:

void bar( std::function< void( foo ) > funcPtr, int foo::* varPtr )
{
    foo myFoo;
    funcPtr( myFoo );
    foo.*varPtr = 13;
}

person Jonathan Mee    schedule 04.06.2014    source источник
comment
@WilliamAndrewMontgomery На самом деле я уже просмотрел C++: указатель на элемент данных класса есть нет конструкции STL.   -  person Jonathan Mee    schedule 04.06.2014
comment
Указатель переменной-члена не соответствует стилю C.   -  person aschepler    schedule 04.06.2014
comment
В вашем вопросе нет ничего из STL.   -  person Jonathan Wakely    schedule 04.06.2014
comment
Что вы пытаетесь достичь?   -  person rubenvb    schedule 04.06.2014
comment
@aschepler, который казался самым четким способом разграничения между оболочкой указателя STL и простым указателем. Если вы считаете, что есть лучший способ изложить это, отредактируйте вопрос.   -  person Jonathan Mee    schedule 04.06.2014
comment
C не поддерживает указатели на члены, поэтому называть их стилем C определенно не самый ясный способ сказать это! Термины, которые вам нужны, — это оболочка вызова для того, что возвращает mem_fn, и указатель на член для int foo::*.   -  person Jonathan Wakely    schedule 04.06.2014


Ответы (2)


Н.Б. В вашем вопросе нет ничего из STL (это библиотека 1990-х годов), std::function и std::mem_fn являются частью стандартной библиотеки C++, что не одно и то же.

std::mem_fn поддерживает функции-члены и переменные-члены, поэтому вы можете просто сделать это, чтобы получить доступ к переменной-члену и установить ее:

foo f;
std::function<int&(foo&)> var( std::mem_fn( &foo::fooVar ) );
var(f) = 1;
person Jonathan Wakely    schedule 04.06.2014
comment
Согласно en.wikipedia.org/wiki/Standard_Template_Library, функционал определенно является частью STL. - person isarandi; 04.06.2014
comment
@isarandi, но std::function и std::mem_fn нет, они новые в C++11 и пришли из Boost, а не из STL. То, что они находятся в том же заголовке, что и что-то еще, не делает их одинаковыми. - person Jonathan Wakely; 04.06.2014
comment
Но это просто новая версия STL, верно? STL является частью стандартной библиотеки C++. А std::function находится в STL-части стандартной библиотеки C++11. По крайней мере, так трактует Википедия. То, откуда оно пришло, не имеет никакого отношения к тому, где оно находится сейчас. - person isarandi; 04.06.2014
comment
Нет, это неправильно, и это не то, что говорит Википедия. Части STL были включены в стандартную библиотеку C++ (но не всю), а другие вещи вошли в стандартную библиотеку C++ позже. Однако эти другие вещи не становятся частью STL. Например, std::function и std::mem_fn не являются частью sgi.com/tech/stl. - person Jonathan Wakely; 04.06.2014
comment
@JonathanWakely Чтобы разобраться в сути моего вопроса, я пытаюсь создать шаблонный сеттер, но это не работает: template< typename T > void bar( std::function< T&( foo& ) > ) при вызове с чем-то вроде bar( std::mem_fn( &foo::fooVar ) ). Возможно, проблема в распаде указателя функции? - person Jonathan Mee; 04.06.2014
comment
@JonathanMee, ваше второе редактирование не требовалось, код в любом случае был действителен (если он не скомпилировался, вам нужен лучший компилятор) - person Jonathan Wakely; 04.06.2014
comment
@JonathanWakely Да, я использую VS2012, так что, возможно, я немного устарел. В своем комменте выше я спрашивал про передачу результата в шаблонную функцию, может проблема опять в моем компиляторе? - person Jonathan Mee; 04.06.2014
comment
Нет, проблема в том, что вы не можете вывести T из аргумента. См. аналогичный сайт stackoverflow.com/a/23900128/981959. Вы не можете вывести T в std::function<T&(foo&)> из чего-то, что не является std::function<T&(foo&)>, потому что набор возможных преобразований, которые могут позволить успешному выводу, бесконечен, а компилятор не может обрабатывать бесконечность (что не является проблемой для вашего компилятора в данном случае). раз мой компилятор тоже не может обрабатывать бесконечность :-) - person Jonathan Wakely; 04.06.2014

В дополнение к функциям-членам std::mem_fn также может обертывать элементы данных и разрешать доступ к ним для чтения. Итак, работает следующее:

void print_fooVar(foo& f, std::function<int(foo)> varAccess)
{
    std::cout << varAccess(f) << std::endl;
}

foo f;
print_fooVar(f, std::mem_fn(&foo::fooVar)); // prints 0

Как упоминает Джонатан Уэйкли в комментариях, вы можете использовать (неуказанный) тип, возвращаемый самим mem_fn, для установки члена данных.

foo f;
std::mem_fn(&foo::fooVar)(f) = 13;

Или превратить его в std::function использование

void bar( foo& f, std::function<int&(foo&)> fooVarSet )
{
    fooVarSet(f) = 26;
}

Если все, что вам нужно, это способ сгенерировать вызываемый объект для установки члена данных fooVar, а не использовать std::mem_fn специально для этого, вы также можете выполнить эту работу с помощью лямбда-выражения.

void bar( foo& f, std::function<void(foo)> funcPtr, 
                  std::function<void(foo&, int)> fooVarSet )
{
    funcPtr( f );
    fooVarSet(f, 13);
}

foo f;
bar(f, std::mem_fn(&foo::fooFunc), [](foo& f, int i) {f.fooVar = i;});

Текущая демонстрация

person Praetorian    schedule 04.06.2014
comment
mem_fn для переменной-члена возвращает ссылку, поэтому вы можете просто mem_fn(&foo::fooVar)(f) = 1; - person Jonathan Wakely; 04.06.2014
comment
@JonathanWakely Да, и я должен был быть более ясным в ответе. Что я не знаю, как сделать, так это преобразовать любой возвращаемый тип mem_fn в std::function, который затем можно использовать для установки члена данных. Я отредактирую ответ. - person Praetorian; 04.06.2014
comment
О, это просто, просто сохраните его в std::function<int&(foo&)> - person Jonathan Wakely; 04.06.2014
comment
@JonathanWakely Я пробовал std::function<int&(foo)>, и это не сработало. Так близко! Спасибо за указатели. - person Praetorian; 04.06.2014