Static Lambdas: Initializing lambdas at compile time
Interesting tricks that he had applied.
Instead of initializing lambda object at program start-up.
Idea:
1.
lambda expression object is generated during run-time;
however, the type itself for sure is completed during compile time.
2.
Extract the lambda expression type thus could be used for constexpr variable.
Steps:
1.
Extract ptr to lambda expression type.
Of course, use template function to deduce :-)
this function is not constexpr due to it's parameter isn't literal type.
--
template<typename T>
typename std::remove_reference<T>::type* GetPtrToLambda(T&& t)
{
return &t;
}
2.
A constexpr template function could extract the type: Wrapper<T> explained later.
--
template<typename T>
constexpr Wrapper<T> GetLambdaWrapper(T*)
{
return {};
}
3.
GetPtrToLambda([](auto i){cout << i << endl;})
will be run on runtime; however, we only need the type at compile time. Trick Paul Fultz did:
--
true ? nullptr : GetPtrToLambda([](auto i){cout << i << endl;});
--i.e, will get a ptr to lambda expression type but point to null.
4.
i.e:
--
>GetLambdaWrapper(true ? nullptr : GetPtrToLambda([](auto i){cout << i << endl;}));
--Now we have the Wrapper<T> while T is the lambda expression type.
5.
Wrapper is straight forward: A stateless Wrapper of size 1 byte. T is the type of lambda expression type.
This works only for stateless lambda expression type.
--
template<typename T>
struct Wrapper
{
template<typename... A>
decltype(auto) operator()(A&&... a) const
{
return reinterpret_cast<const T&>(*this)(std::forward<A>(a)...);
}
};
6.
The binary size of the code is roughly the same as simply do:
auto lambda = [](auto i){cout << i << endl;};
7.
Full code:
----
#include <iostream>
#include <type_traits>
using namespace std;
template<typename T>
typename std::remove_reference<T>::type* GetPtrToLambda(T&& t)
{
return &t;
}
template<typename T>
struct Wrapper
{
template<typename... A>
decltype(auto) operator()(A&&... a) const
{
return reinterpret_cast<const T&>(*this)(std::forward<A>(a)...);
}
};
template<typename T>
constexpr Wrapper<T> GetLambdaWrapper(T*)
{
return {};
}
constexpr auto lambda = GetLambdaWrapper(true ? nullptr : GetPtrToLambda(
[](auto i){cout << i << endl;}));
int main()
{
lambda(42);
}
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.