Reputation: 523
I am attempting to build a constexpr lambda that uses a member function pointer as part some type of registration process.
The problem is the outermost function that is part of that process is not constexpr which makes the argument (the function pointer) not valid in a constexpr context.
Can that createLambda call and variable storage (invokable) be made constexpr within that function (maybe pass the whole function point as a template argument?) and would I even save anything by making the lambda constexpr inside of "passthrough"?
A basic example is below. In the real code, the lambda is part of abstraction converting to an "any" type.
#include <iostream>
#include <map>
#include <functional>
std::map<uint64_t, std::function<int(void*)>> g_map;
class Data
{
public:
int returnData()
{
return m_data;
}
int m_data = 5;
};
template<
typename ReturnType,
typename ClassType
>
constexpr auto createLambda(ReturnType(ClassType::* method)(void))
{
return [=](void* object) -> int
{
return (reinterpret_cast<ClassType*>(object)->*method)();
};
}
template<
typename ReturnType,
typename ClassType
>
auto passthrough(ReturnType(ClassType::* method)(void)) // Function cannot be constexpr
{
auto invokable = createLambda(method); // This is not valid, what are my alternatives to make this possible?
constexpr uint64_t someOtherTask = 1 + 2;
g_map[someOtherTask] = invokable;
return invokable;
}
int main()
{
Data testData;
constexpr auto invoke = createLambda(&Data::returnData); // Works Fine
auto invoke2 = passthrough(&Data::returnData); // Does Not Work
testData.m_data = 7;
std::cout << invoke(&testData) << std::endl;
testData.m_data = 8;
std::cout << invoke2(&testData) << std::endl;
testData.m_data = 9;
std::cout << g_map[1 + 2](&testData) << std::endl;
return 0;
}
A concern I have is binary size bloat when used with literally thousands of member methods.
Assume a ceiling of C++17 standard and that the user should only have to make a single call to passthrough per member method (arguments can change if needed).
Upvotes: 1
Views: 344
Reputation: 68
If you want to make next statement constexpr
auto invokable = createLambda(method);
Pass method as non-type template argument
template<auto method>
auto passthrough() // Function cannot be constexpr
{
constexpr auto invokable = createLambda(method); // This is not valid, what are my alternatives to make this possible?
constexpr uint64_t someOtherTask = 1 + 2;
g_map[someOtherTask] = invokable;
return invokable;
}
And the call it like this
auto invoke2 = passthrough<&Data::returnData>();
The reason why you can not do auto invokable = createLambda(method);
when method
is function argument, because function arguments are not constexpr. Since, function is not scope of creating argument object.
If method
was created inside passthrough
it would work. Template argument is guaranteed to be evaluted at compile-time that's the reason why it can be used in function in constepxr context even, if was created outside of function
Code snippet in godbolt compiler https://godbolt.org/z/c6aqWW9j6
Upvotes: 2