Соответствие std :: bind при предоставлении указателя на метод и объекта производного типа

Этот вопрос в основном является последствием этот ответ я дал. Я только что понял, что формулировка в стандарте, кажется, опускает несколько случаев. Рассмотрим этот кусок кода:

#include <iostream>
#include <functional>

struct foo
{
void f(int v) { std::cout << v << std::endl; }
};

struct bar : foo {};

int main()
{
bar obj;
std::bind(&foo::f, obj, 1)();
}

Стандарт описывает в 20.8.9.1.2 эффект std::bind и что происходит, когда он вызывается. Переходит к 20.8.2, соответствующая часть:

20.8.2 Требования [func.require]

1 определять ВЫЗОВ(f, t1, t2, ..., tN) следующее:

(t1.*f)(t2, ..., tN) когда f указатель на функцию-член класса T а также t1 является объектом типа T или ссылка на объект типа T или ссылка на объект типа, производного от T;

((*t1).*f)(t2, ..., tN) когда f указатель на функцию-член класса T а также t1 не является одним из типов, описанных в предыдущем пункте;

t1.*f когда N == 1 а также f указатель на данные члена класса T а также t1 является объектом типа T или ссылка на объект типа T или ссылка на объект типа, производного от T;

(*t1).*f когда N == 1 а также f указатель на данные члена класса T а также t1 не является одним из типов, описанных в предыдущем пункте;

f(t1, t2, ..., tN) во всех остальных случаях.

Читая это, кажется, что можно разрешить три случая для первого элемента списка:

  • t1 является объектом типа T
  • или ссылка на объект типа T
  • или ссылка на объект типа, производного от T

но в моем примере это не так. Это тип, полученный из T, но без ссылки. Не должны ли перечисленные выше случаи быть:

  • t1 является объектом типа T
  • или объект типа, производного от T
  • или ссылка на объект типа T
  • или ссылка на объект типа, производного от T

Конечно, то же самое относится и к третьему пункту списка в 20.8.2.

Вопрос 1: Поскольку и GCC, и Clang принимают мой код, мне интересно, является ли это отчет о дефекте по сравнению со стандартом или я просто читаю его неправильно.

Вопрос 2: С множественным / виртуальным наследованием, даже если тип является производным от T, это может быть не просто возможно позвонить (t1.*f)(...) на этом, верно? Это также то, что меня должно беспокоить, или стандарт четко определяет «производные» в данном контексте?

4

Решение

Пункт 20.8.9.1.3 Стандарта C ++ 11 определяет эффекты вызова std::bind() с точки зрения INVOKE() псевдо-функции сюда:

Возвращает: Упаковщик переадресации g со слабым типом результата (20.8.2). Эффект g(u1, u2, ..., uM) должен быть INVOKE (fd, std::forward<V1>(v1), std::forward<V2>(v2), ..., std::forward<VN>(vN),
result_of<FD cv & (V1, V2, ..., VN)>::type)

Обратите внимание, что призыв к std::forward<> всегда будет возвращать тип ссылки, будь то ссылка lvalue или ссылка rvalue. Согласно пунктам 20.2.3 / 1-2, фактически:

template <class T> constexpr T&& forward(typename remove_reference<T>::type& t) noexcept;

template <class T> constexpr T&& forward(typename remove_reference<T>::type&& t) noexcept;

Возвращает: static_cast<T&&>(t)

Следовательно INVOKE псевдо-функция (будьте осторожны: не bind() функция!) будет вызываться здесь со ссылками, и это подтверждается приведенным вами определением.

Я считаю, что сам Стандарт никогда не использует INVOKE() псевдофункция (это просто некоторый внутренний формализм) с объектами (не ссылками на объект) типа, производного от T,

Однако это не означает, что вы не можете вызвать std::bind() или другие функции, определение которых в свою очередь дается в терминах INVOKE() с объектом (не ссылкой на объект) типа, полученного из T,

3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]