Вектор std :: function и список инициализации в классе [duplicate]

Вот соответствующие цитаты, но окончательный ответ во многом зависит от интерпретации.

N3797 6.4.2 / 2:

Условие должно быть цельного типа, типа перечисления или типа класса , Если тип класса, условие контекстно неявно преобразуется (раздел 4) в интегральный или перечисляемый тип.

4/5:

Определенные языковые конструкции требуют преобразования в значение, имеющее один из определенного набора типов, соответствующих конструкции. Выражение e типа класса E, появляющееся в таком контексте, называется , контекстно неявно преобразованным в заданным типом T и хорошо сформированным тогда и только тогда, когда e может неявно преобразуется в тип T, который определяется следующим образом: E выполняется поиск функций преобразования, возвращаемым типом которых является cv T или ссылка на cv T, что T разрешено контекстом. Должен быть ровно один такой T.

14.5.2 / 6:

Специализация функции преобразования не найдена при поиске по имени. Вместо этого рассматриваются все шаблоны функций преобразования, видимые в контексте использования. Для каждого такого оператора, если вывод аргумента преуспевает (14.8.2.3), полученная специализация используется, как если бы она была найдена путем поиска по имени.

14.5.2 / 8:

Разрешение перегрузки (13.3.3.2) и частичное упорядочение (14.5.6.2) используются для выбора наилучшей функции преобразования между несколькими специализациями шаблонов функций преобразования и / или функциями преобразования без шаблона.

Интерпретация 1: 4/5 гласит «функции преобразования», а не «функции преобразования и шаблоны функций преобразования». Поэтому Var::operator int() const является единственным вариантом, а clang является правильным.

Интерпретация 2 [слабый?]: 14.5.2 требует от нас сравнить шаблон функции преобразования путем разрешения перегрузки и частичного упорядочения на том же начальном как функция преобразования без шаблона. Они сравнивают специализированные функции и функции шаблонов, а не шаблоны функций, поэтому мы будем делать вывод аргумента шаблона. Вычисление аргумента шаблона для шаблона функции преобразования требует целевого типа. Хотя у нас обычно есть более четкий тип цели, в этом случае мы просто попробуем (теоретически все) все типы в наборе допустимых типов. Но ясно, что функция без шаблона является лучшей жизнеспособной функцией, которая включает все специализированные шаблоны, поэтому разрешение перегрузки выбирает функцию без шаблона. clang является правильным.

Интерпретация 3: Поскольку для разрешения перегрузки требуется вычет аргумента шаблона, а вывод аргумента шаблона требует известного целевого типа, сначала следует рассмотреть семантику 4/5, а затем ее преобразованный тип (если любой) может использоваться для процесса разрешения перегрузки. 14.5.2 требует рассмотрения шаблона функции преобразования, но затем мы обнаруживаем, что существует несколько допустимых типов T, для которых у нас есть функция преобразования T [эта функция, возможно, является специализированной функцией). Программа плохо сформирована, поэтому g ++ корректна.

113
задан Max 17 January 2015 в 13:30
поделиться

3 ответа

Нестатическую функцию-член нужно вызывать с объектом. То есть он всегда неявно передает «этот» указатель в качестве своего аргумента.

Поскольку ваша подпись std::function указывает, что ваша функция не принимает никаких аргументов (<void(void)>), вы должны bind первый (и единственный) аргумент.

std::function<void(void)> f = std::bind(&Foo::doSomething, this);

Если вы хотите связать функцию с параметрами, вам нужно указать заполнители:

using namespace std::placeholders;
std::function<void(int,int)> f = std::bind(&Foo::doSomethingArgs, this, _1, _2);

Или , если ваш компилятор поддерживает C ++ 11 lambdas:

std::function<void(int,int)> f = [=](int a, int b) {
    this->doSomethingArgs(a, b);
}

(у меня нет компилятора C ++ 11 под рукой прямо сейчас , поэтому я могу " t проверить это.)

200
ответ дан Max 22 August 2018 в 12:31
поделиться
  • 1
    Поскольку я не зависим от повышения, я буду использовать лямбда-выражения;) Тем не менее спасибо! – Christian Ivicevic 28 September 2011 в 13:01
  • 2
    @AlexB: Boost.Bind не использует ADL для заполнителей, он помещает их в анонимное пространство имен. – ildjarn 28 September 2011 в 17:34
  • 3
    Я рекомендую избегать глобального захвата [=] и использовать [this], чтобы сделать более понятным захваченное (Скотт Мейерс - Эффективный современный C ++ Глава 6. пункт 31 - Избегать режимов захвата по умолчанию) – Max Raskin 29 August 2016 в 13:57

Вам нужно

std::function<void(Foo*)> f = &Foo::doSomething;

, чтобы вы могли вызвать его на любом экземпляре, или вам нужно связать конкретный экземпляр, например this

std::function<void(void)> f = std::bind(&Foo::doSomething, this);
57
ответ дан Armen Tsirunyan 22 August 2018 в 12:31
поделиться
  • 1
    Спасибо за этот замечательный ответ: D Точно, что мне нужно, я не мог найти, как специализировать функцию std :: для вызова функции-члена на любом экземпляре класса. – penelope 5 April 2018 в 17:03

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

class MyClass
{
public:
    void MemberFunc(int value)
    {
      //do something
    }
};

// Store member function binding
auto callable = std::mem_fn(&MyClass::MemberFunc);

// Call with late supplied 'this'
MyClass myInst;
callable(&myInst, 123);

. Каким будет тип хранилища без auto ? Что-то вроде этого:

std::_Mem_fn_wrap<void,void (__cdecl TestA::*)(int),TestA,int> callable

Вы также можете передать это хранилище функций стандартным связям функций

std::function<void(int)> binding = std::bind(callable, &testA, std::placeholders::_1);
binding(123); // Call

Предыдущие и будущие примечания: более старый интерфейс std :: mem_func , но с тех пор он устарел. Существует предложение, post C ++ 17, чтобы сделать указателем на функции-члены, вызываемые . Это было бы очень приятно.

5
ответ дан Greg 22 August 2018 в 12:31
поделиться
  • 1
    @Danh std::mem_fn удален не ; куча ненужных перегрузок. С другой стороны, std::mem_fun устарел с C ++ 11 и будет удален с C ++ 17. – Max Truxa 3 November 2016 в 16:47
  • 2
  • 3
    @ Danh Внимательно прочитайте DR . 12 из 13 перегрузок были удалены DR. Это последнее не было (и не будет, ни на C ++ 11, ни на C ++ 14). – Max Truxa 3 November 2016 в 17:01
  • 4
    Почему голос? В каждом ответе говорилось, что вы должны привязать экземпляр класса. Если вы создаете систему привязки для отражения или сценариев, вы не захотите этого делать. Этот альтернативный метод действителен и актуальен для некоторых людей. – Greg 4 November 2016 в 00:06
  • 5
    Спасибо Danh, я редактировал некоторые комментарии о связанных прошлых и будущих интерфейсах. – Greg 7 November 2016 в 07:39
Другие вопросы по тегам:

Похожие вопросы: