Равенство указателей на функции, которые указывают на лямбда-функцию - PullRequest
0 голосов
/ 28 января 2019

Мне интересно, гарантируется ли следующее поведение (см. Утверждения) стандартом C ++?Кажется, что он работает под последними версиями clang и gcc, но я все еще не уверен, определил ли его стандартное поведение или реализация.

#include <cassert>
#include <functional>

struct test
{
    using fn_ptr_t = int(*)(int);

    fn_ptr_t fn_ = nullptr;

    template<auto Fun>
    void assign() noexcept
    {
        fn_ = +[](int i)
        {
            return std::invoke(Fun, i);
        };
    }
};

int fun(int i) { return i; }
int gun(int i) { return i; }

int main()
{
    test t0, t1, t2;

    t0.assign<&fun>();
    t1.assign<&fun>();
    t2.assign<&gun>();

    assert(t0.fn_ == t1.fn_);
    assert(t0.fn_ != t2.fn_);

    return 0;
}

Я обнаружил, что стандарт говорит следующее о указателях функций:

C ++ 03 5.10 / 1 [expr.eq]: ... Указатели на объекты или функции одного типа (после преобразования указателей) можно сравнивать на равенство.Два указателя одного типа сравниваются равными, если и только если они оба равны нулю, оба указывают на одну и ту же функцию или оба представляют один и тот же адрес (3.9.2).

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

1 Ответ

0 голосов
/ 28 января 2019

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

template <typename>
auto get() { return []{}; }

auto l1 = get<int>();
auto l2 = get<long>();
auto l3 = get<int>();

static_assert(std::is_same_v<decltype(l1), decltype(l2)>); // fails
static_assert(std::is_same_v<decltype(l1), decltype(l3)>); // passes

// caveat: needs C++20
l1 = l2; // no, different lambdas
l1 = l3; // ok, same lambda

В вашем случае указатель функции t0 и t1 одинаков, поскольку они оба были назначены assign<&fun>, в которому лямбды всегда один и тот же тип.

Поскольку они имеют одинаковый тип, они имеют одинаковый operator(), и поэтому оба указателя функций одинаковы (они указывают на один и тот же operator()).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...