Подтвердить что ты не робот

Std:: function constructor и nullptr

Почему следующий код печатает "0" в качестве вывода?

#include <functional>
#include <iostream>

int main()
{
    typedef void (*fp_t)();

    fp_t fp = nullptr;

    std::function<void()> f = fp;
    std::cout << (f == nullptr) << '\n';
}

Я тестировал его как с gcc 4.7.2, так и с MSVC-11.0.

Я думаю, что он должен печатать "1" из-за следующей цитаты из стандарта:

ISO/IEC 14882: 2011

20.8.11.2.1 function construct/copy/destroy [func.wrap.func.con]

template<class F> function(F f);
template<class F, class A> function(allocator_arg_t, const A& a, F f);

...

8 Постусловия: !*this, если выполнено одно из следующих условий: - f - NULLуказатель функции. - f является указателем NULL для члена. - f - это экземпляр шаблона класса функций и !f

4b9b3361

Ответ 1

Я думаю, что это ошибка. В соответствии с пунктом 20.8.11.2.6/1 стандарта С++ 11:

template <class R, class... ArgTypes>
bool operator==(const function<R(ArgTypes...)>& f, nullptr_t) noexcept;

template <class R, class... ArgTypes>
bool operator==(nullptr_t, const function<R(ArgTypes...)>& f) noexcept;

1 Возвращает: !f.

Следовательно, (f == nullptr) должен оцениваться до true тогда и только тогда, когда !f оценивается как true. Затем в пункте 20.8.11.2.1/8 указывается:

template<class F> function(F f);
template <class F, class A> function(allocator_arg_t, const A& a, F f);

[...]

8 Постусловия: !*this если выполнено одно из следующих значений:

- f является указателем функции NULL.

     

[...]

Так как fp является указателем на нулевую функцию, вышеприведенный параграф должен гарантировать, что после инициализации f из fp выражение !f оценивается как true. Это, в свою очередь, означает, что сравнение с nullptr должно возвращать true (в соответствии с § 20.8.11.2.6/1).

Что по очереди означает, что это ошибка.

Ответ 2

Не ответ, но некоторые подробности (gcc) слишком большие для комментария:

Функция проверяется на достоверность с помощью

template<typename _Signature>
  static bool
  _M_not_empty_function(const function<_Signature>& __f)
  { return static_cast<bool>(__f); }

template<typename _Tp>
  static bool
  _M_not_empty_function(const _Tp*& __fp)
  { return __fp; }

template<typename _Class, typename _Tp>
  static bool
  _M_not_empty_function(_Tp _Class::* const& __mp)
  { return __mp; }

template<typename _Tp>
  static bool
  _M_not_empty_function(const _Tp&)
  { return true; }

Вероятно

template<typename _Tp>
  static bool
  _M_not_empty_function(const _Tp*& __fp)
  { return __fp; }

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

template<typename _Tp>
    static bool
    M_not_empty_function(const _Tp*& __fp)
    { return __fp; }

int main()
{
    typedef void (*fp_t)();
    fp_t fp = nullptr;
    return  M_not_empty_function(fp);
}

генерирует

error: no matching function for call to 'M_not_empty_function(void (*&)())'
note: candidate is:
note: template<class _Tp> bool M_not_empty_function(const _Tp*&)
note:   template argument deduction/substitution failed:
note:   types 'const _Tp' and 'void()' have incompatible cv-qualifiers