Constexpr lambda实现 - 这是如何工作的?

时间:2017-02-15 18:14:07

标签: c++ templates lambda constexpr

在执行一项任务时,我遇到了这个棘手的实现,它允许你制作constexpr lambdas(不允许开箱即用):

Crazy constexpr lambdas implementation article

它基本上归结为这种实现:

template<class F>
struct wrapper
{
    //static_assert(std::is_empty<F>(), "Lambdas must be empty");
    template<class... Ts>
    decltype(auto) operator()(Ts&&... xs) const
    {
        return reinterpret_cast<const F&>(*this)(std::forward<Ts>(xs)...);
    }
};

struct wrapper_factor
{
    template<class F>
    constexpr wrapper<F> operator += (F*)
    {
        return{};
    }
};

struct addr_add
{
    template<class T>
    friend typename std::remove_reference<T>::type* operator+(addr_add, T &&t)
    {
        return &t;
    }
};
#define STATIC_LAMBDA wrapper_factor() += true ? nullptr : addr_add() + []

使用

const constexpr auto add_one = STATIC_LAMBDA (/*i believe you can pass arguments here but i havent tried*/) -> bool
{
    //do stuff
    return stuff;
};

我有两个问题:

  1. 我需要注释掉static_assert,因为“std :: is_empty&lt; _Ty&gt;':没有合适的默认构造函数”,即使没有创建这个lambda的任何实例。谁知道为什么?

  2. 这是如何工作的?我跟着所有课程的流程,我明白了

  3. a)这部分

    true ? nullptr : addr_add() + [] your_lambda
    

    返回我们想要lambda的类型的nullptr(进一步称为“correct_type”)

    b)wrapper_factory将此nullptr作为correct_type,构造包装器。此包装器是默认初始化的。

    c)operator()中的包装器将他被调用的参数(在/ * i相信... / *位置传递)转发给一个对象,该对象是“将此指针转换为correct_type的包装器”。

    现在,要调用的例程实际传递的信息在哪里?我只能看到默认创建的空包装器,它被重新解释为某种lambda类型并通过()调用。

    祝你好运

    Marcin K。

1 个答案:

答案 0 :(得分:0)

请考虑此代码

#include <type_traits>

template<class F>
struct wrapper
{
    static_assert(std::is_empty<F>::value, "Lambdas must be empty");
    template<class... Ts>
    decltype(auto) operator()(Ts&&... xs) const
    {
        return reinterpret_cast<const F&>(*this)(std::forward<Ts>(xs)...);
    }
};

struct wrapper_factor
{
    template<class F>
    constexpr wrapper<F> operator += (F*)
    {
        return{};
    }
};

struct addr_add
{
    template<class T>
    friend typename std::remove_reference<T>::type *operator+(addr_add, T &&t)
    {
        return &t;
    }
};

#define STATIC_LAMBDA wrapper_factor() += true ? nullptr : addr_add() + []

const constexpr auto add_one = STATIC_LAMBDA(auto x)
{
    return x + 1;
};

int main()
{
    int a = 1;
    int b = add_one(a);

    return 0;
}

因此,在MSVS2015中,add_one报告为constexpr wrapper<type> add_one = {} 但在主要内容中,add_one(a)报告为int wrapper<lambda []auto (auto x)->auto>::operator() <int &>(int &xs) const 您可以看到*operator+中的友元函数addr_add返回指向lambda函数的指针。 lambda函数定义是隐含的。包装器struct operator()中的可变参数模板将模仿lambda参数。

这是你想知道的吗?