:: std :: function

时间:2018-12-30 12:56:56

标签: c++ metaprogramming c++17 template-meta-programming constexpr

我正在寻找可在constexpr中使用的:: std :: function。 用例:我有一个函数,该函数以函数指针作为参数,第二个函数将lambda传递给第一个函数。两者在编译时都是完全可执行的,因此我想对其进行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);
}

但是,这仅起作用,因为我将lambda转换为函数指针,并且当然无法捕获lambda,如第二个示例所示。谁能给我一些有关捕获lambda的方法的提示?

这将演示用例:

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*/);
}

谢谢, 杰克

2 个答案:

答案 0 :(得分:4)

  

我正在寻找可在constexpr中使用的:: std :: function

在这里停止。不可能。 std::function是一个多态包装函数。无状态Lambda,有状态Lambda,函子,函数指针,函数引用-它们都可以构建有效的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.");
}

答案 1 :(得分:3)

C ++ 20发生了很多变化-最重要的是,您现在可以在constexpr上下文中使用动态内存和虚拟函数。这完全可以构建一个std :: function的constexpr版本。这是一个概念验证(很长,没有副本或移动构造函数,因此请请勿原样使用)。它在clang 10下运行,运行代码here。我没有在其他编译器下尝试过它,值得注意的是,目前没有一个主要的编译器声称拥有完整的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;
}