cpp-ru / ideas

Идеи по улучшению языка C++ для обсуждения
https://cpp-ru.github.io/proposals
Creative Commons Zero v1.0 Universal
90 stars 0 forks source link

Починить std::invoke_result_t #413

Open apolukhin opened 3 years ago

apolukhin commented 3 years ago

Перенос предложения: голоса +3, -0 Автор идеи: Дмитрий

В шаблоне-псевдониме std::invoke_result_t есть ошибка, из-за которой он не всегда работает там, где работает обычная std::invoke_result. Хотя, очевидно, они должны быть полностью взаимозаменяемы.

Суть проблемы:

#include <type_traits>

// Мы знаем, что {Xs...} == {F, Args...}, но не хотим упоминать F явно.
template <typename... Xs>
void f (Xs...)
{
    // Всё работает.
    using good = typename std::invoke_result<Xs...>::type;
    // Ошибка компиляции.
    using bad = std::invoke_result_t<Xs...>; // !
}

struct call
{
    int operator () () const
    {
        return 0;
    }
};

int main()
{
    f(call{});
}

Получается, что псевдоним std::invoke_result_t нарушает "сигнатуру" оригинальной метафункции std::invoke_result, ломая тем самым вполне корректный код.

Думаю, что правильная реализация будет выглядеть так:

// Правильно.
template <typename... Xs>
using invoke_result_t = typename std::invoke_result<Xs...>::type;

А текущая реализация ошибочна:

// Неправильно.
template <typename X, typename... Xs>
using invoke_result_t = typename std::invoke_result<X, Xs...>::type;
apolukhin commented 3 years ago

Олег Фатхиев, 5 марта 2019, 11:16 Текущая реализация не ошибочна, std::invoke_result_t обязан принимать строго больше 0 параметров. Проблема, видимо, в overload resolution для алиасов, они не умеют принимать variadic pack-и в таком случае. Кажется подобная проблема уже была в gcc, могу ошибаться. Интересно то, что этот код работает в msvc. Нужно разобраться, что об этом говорит стандарт.

Дмитрий, 6 марта 2019, 12:14 Олег Фатхиев, std::invoke_result_t — это просто псевдоним. Он прокинет аргументы в std::invoke_result, и если их там окажется 0, то вывалится ошибки.

yndx-antoshkka, 5 марта 2019, 18:33 Это уберёт симптом, но не вылечит болезнь. Надо на уровне языка сделать так, чтобы текущая реализация работала. Тогда автоматически исправится множество подобных проблем.

Спрошу у специалистов по ядру языка, что можно с этим сделать на данный момент.

yndx-antoshkka, 5 марта 2019, 20:23 Скинули ссылку на проблему: https://wg21.link/CWG1430

Дмитрий, 6 марта 2019, 12:22 yndx-antoshkka, я внимательно прочитал ссылку, но не понял, какие оттуда следуют выводы.

Можем ли мы "вылечить болезнь"? Если не можем, то нужно хотя бы "устранить симптом", то есть все псевдонимы метафункций, которые ломают логичный и осмысленный код.

apolukhin commented 3 years ago

Первопричину кажется что пока не починить, придётся чинить симптомы