Я ищу :: 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.
Есть способ преобразовать захватывающую лямбду в указатель на функцию.
@ user1095108 Я знаю этот способ, однако, насколько я знаю, вы не можете использовать его в constexpr





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 (выделение памяти, приведение, ...), но возможен обходной путь / обмен.
Хм ... Я сомневаюсь в этом. Нет смысла изменять сам std::function на constexpr, так как это, скорее всего, может стать критическим изменением. Однако есть веская причина предоставить эквивалент constexpr для случаев, когда общая вызываемая оболочка и желательна, и гарантированно ссылается на один и тот же объект (который сам известен во время компиляции) в течение всего времени его существования.
вы не можете сделать constexpr-версию std :: function. период. std :: function выполняет стирание типа, что невозможно с constexpr.
Итак, в 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++.
В порядке! Вы можете прояснить свой вопрос, чтобы указать на это - прямо сейчас он не упоминает стандарт и помечен как "C++ - 17"
Как вы собираетесь его использовать? Почему бы просто не использовать
auto test = [](int i) -> int { return i + 1; };?