Constexpr версия :: std :: function

Я ищу :: std :: function, который можно использовать в constexpr. Пример использования: у меня есть функция, которая принимает указатель функции в качестве аргумента, и вторая, которая передает лямбда-выражение первой функции. Оба являются полностью исполняемыми во время компиляции, поэтому я хочу объединить их. Например:

template <class _Type>
class ConstexprFunctionPtr
{
    private:
        using Type = typename ::std::decay<_Type>::type;
        const Type function;

    public:
        constexpr inline
        ConstexprFunctionPtr(const Type f)
        : function(f)
        { }

        template <typename... Types>
        constexpr inline
        auto
        operator() (Types... args)
        const {
            return function(args... );
        }
};

constexpr inline
void
test()
{
    ConstexprFunctionPtr<int(int)> test([](int i) -> int {
        return i + 1;
    });
    int i = test(100);

    ConstexprFunctionPtr<int(int)> test2([=](int i) -> int {
        return i + 1;
    });
    i = test2(1000);
}

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

Это продемонстрирует вариант использования:

constexpr
void
walkOverObjects(ObjectList d, ConstexprFunctionPtr<void(Object)> fun) {
// for i in d, execute fun
}

constexpr
void
searchObjectX(ObjectList d) {
walkOverObjects(d, /*lambda that searches X*/);
}

Спасибо, Джек

Обновлять: Спасибо, что указали на решение C++ 20, однако я хочу, чтобы оно работало под C++ 14.

Как вы собираетесь его использовать? Почему бы просто не использовать auto test = [](int i) -> int { return i + 1; };?

Fureeish 30.12.2018 14:02

Есть способ преобразовать захватывающую лямбду в указатель на функцию.

user1095108 30.12.2018 14:03

@ user1095108 Я знаю этот способ, однако, насколько я знаю, вы не можете использовать его в constexpr

user10043112 30.12.2018 15:40
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
3
2 478
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

I am in search of a ::std::function usable in constexpr

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

Если вам просто нужен параметр универсальной функции времени компиляции, вы можете просто использовать шаблоны

template<class functor_type>
class my_generic_function_consumer_class{

   using decayed_function_type = typename std::decay_t<functor_type>;

   decayed_function_type m_functor;

};

В рассматриваемом коде просто примите универсальный функтор и проверьте его с помощью static_assert:

template<class function_type>
constexpr void walkOverObjects(ObjectList d, function_type&& fun) {
    static_assert(std::is_constructible_v<std::function<void(ObjectList), function_type>>,
                  "function_type given to walkOverObjects is invalid.");
}
"создание эквивалента времени компиляции - пустая трата времени".. Я не понимаю вашей точки зрения, std::variant "может" иметь те же аргументы, что и constexpr. Стирание типа std::function и другие функции могут использовать функции, еще не совместимые с constexpr (выделение памяти, приведение, ...), но возможен обходной путь / обмен.
Jarod42 31.12.2018 00:33

Хм ... Я сомневаюсь в этом. Нет смысла изменять сам std::function на constexpr, так как это, скорее всего, может стать критическим изменением. Однако есть веская причина предоставить эквивалент constexpr для случаев, когда общая вызываемая оболочка и желательна, и гарантированно ссылается на один и тот же объект (который сам известен во время компиляции) в течение всего времени его существования.

Justin Time - Reinstate Monica 23.07.2019 22:28

вы не можете сделать constexpr-версию std :: function. период. std :: function выполняет стирание типа, что невозможно с constexpr.

David Haim 24.07.2019 10:34

Итак, в C++ 20 многое изменилось - самое главное, теперь вы можете использовать динамическую память и виртуальные функции в контекстах constexpr. Это делает возможным создание constexpr-версии std :: function. Вот доказательство концепции (оно длинное и не имеет конструкторов копирования или перемещения, поэтому, пожалуйста, не используйте это как есть). Он компилируется под clang 10, выполняя код здесь. Я не пробовал использовать это в других компиляторах, и стоит отметить, что ни один из основных компиляторов не заявляет, что в настоящее время имеет полную реализацию C++ - 20.

#include <type_traits>
#include <utility>
#include <functional>

template<typename Ret, typename... Args> struct _function{
    constexpr virtual Ret operator()(Args...) const = 0;
    constexpr virtual ~_function() = default;
};

template<typename F, typename Ret, typename... Args> struct _function_impl : public _function<Ret,Args...>{
    F f;
    constexpr Ret operator()(Args... args) const override {
        return f(std::forward<Args>(args)...);
    }
    constexpr _function_impl(F&& f):f(f){}
};

template<typename > struct function;

template<typename Ret, typename... Args> struct function<Ret (Args...)>{
    _function<Ret,Args...> *real_f{nullptr};
    constexpr Ret operator()(Args... args) const {
        return real_f->operator()(std::forward<Args>(args)...);
    }

    constexpr ~function(){
        if (real_f) delete real_f;
    }

    template<typename F>
    constexpr function(F&& f):real_f(new _function_impl<std::decay_t<F>,Ret,Args...>(std::move(f))){}

};

template<typename Ret, typename... Args>
constexpr Ret call_f_2(const function<Ret(Args...)> &f, Args... a){
    return f(std::forward<Args>(a)...);
}

template<typename F, typename... Args>
constexpr decltype(auto) call_f(F && f, Args&&... a){
    using Ret = std::invoke_result_t<std::decay_t<F>,Args...>;
    function<Ret(Args...)> f2 = std::move(f);
    return call_f_2<Ret,Args...>(f2,a...);
}

int main(){
    constexpr int c = 3;
    constexpr int i = call_f([c](int j) constexpr {return c + j;},4);
    return i;
}

Я ценю ваш ответ, но мне нужно было решение для C++ 11/14, поэтому я не пометил его как «правильный». Но я уверен, что ваши усилия будут оценены людьми, ищущими решение в современных версиях C++.

user10043112 13.06.2020 10:58

В порядке! Вы можете прояснить свой вопрос, чтобы указать на это - прямо сейчас он не упоминает стандарт и помечен как "C++ - 17"

Mae Milano 14.06.2020 19:52

Другие вопросы по теме