I want to create several instantiations of templated-lambda in one place. The number of instantiations and parameters of each are known at compilation time so I assume that this could be possible. This is generic illustration of what I want to do:
enum class Format
{
FORMAT_1,
FORMAT_2
//, ...
};
template<Format F>
struct SomeData
{
//...
};
template < template<Format> typename Processing >
struct ProcessingForAllFormats
{
Processing<Format::FORMAT_1> processingObject1;
Processing<Format::FORMAT_2> processingObject2;
//...
};
template < template<Format> typename Processing >
decltype(auto) makeProcessingForAllFormats(Processing lambda)
{
//I know this function is completely wrong as
//concrete instantation needs concrete type as an argument
//instead of a template
return ProcessingForAllFormats<Processing>();
}
int main() {
auto processing = makeProcessingForAllFormats(
[](SomeData<auto> data) {/*...*/}
);
return 0;
}
This is simplified image of my problem. In one word - I want to store instantiations of processings for any SomeData objects for future use. I don't know if it is possible in C++14 or even C++17. And I know this would be easy if I use dynamic polymorphism instead of static one but performance means a lot for me in this case.
EDIT:
As TartanLlama noticed - using functors is indeed simpler to implement but much harder to use. I treat Format
, SomeData
and ProcessingForAllFormats
like if it was a part of library/API and I want give user of that "liblary" as much ease-of-use as I can. Lambdas are intended to provide that. @AndyG's sugestion is useful - for lambdas ProcessingForAllFormats implementation must be diferent. But I don't have idea if lambda-templates in C++14/17 are powerful enough to build such API.
How about wrapping generic lambda with interface restricted to your desired types:
enum class Format
{
FORMAT_1,
FORMAT_2
//, ...
};
template<Format F>
struct SomeData
{
//...
};
template <typename GenericProcessing, Format format>
struct Restrictor
{
Restrictor(GenericProcessing genericProcessingObject)
: genericProcessingObject(genericProcessingObject)
{}
decltype(auto) operator()(SomeData<format> data)
{
return genericProcessingObject(data);
}
private:
GenericProcessing genericProcessingObject;
};
template <typename GenericProcessing>
struct ProcessingForAllFormats
{
Restrictor<GenericProcessing, Format::FORMAT_1> processingObject1;
Restrictor<GenericProcessing, Format::FORMAT_2> processingObject2;
//...
ProcessingForAllFormats(GenericProcessing genericProcessingObject)
: processingObject1(genericProcessingObject)
, processingObject2(genericProcessingObject)
//...
{}
};
template <typename GenericProcessing>
decltype(auto) makeProcessingForAllFormats(GenericProcessing genericProcessingObject)
{
return ProcessingForAllFormats<GenericProcessing>(genericProcessingObject);
}
int main() {
auto processing = makeProcessingForAllFormats(
[](auto data) {/*...*/});
processing.processingObject1(SomeData<Format::FORMAT_1>{}); // ok
//processing.processingObject1(SomeData<Format::FORMAT_2>{}); // fail by design, expects SomeData<Format::FORMAT_1>
//processing.processingObject2(SomeData<Format::FORMAT_1>{}); // fail by design, expects SomeData<Format::FORMAT_2>
processing.processingObject2(SomeData<Format::FORMAT_2>{}); // ok
}