C++ - создать корзину для любой лямбды
Я хочу создать несколько экземпляров шаблонной лямбды в одном месте. Количество экземпляров и параметры каждого из них известны во время компиляции, поэтому я предполагаю, что это возможно. Это общая иллюстрация того, что я хочу сделать:
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;
}
Это упрощенное изображение моей проблемы. Одним словом - я хочу хранить экземпляры обработок для любых объектов SomeData для будущего использования. Я не знаю, возможно ли это в C++14 или даже в C++17. И я знаю, что это было бы легко, если бы я использовал динамический полиморфизм вместо статического, но производительность в этом случае для меня много значит.
РЕДАКТИРОВАТЬ:
Как заметил TartanLlama - использование функторов действительно проще в реализации, но намного сложнее в использовании. Я лечу Format
, SomeData
а также ProcessingForAllFormats
например, если это было частью библиотеки /API, и я хочу дать пользователю этой "библиотеки" как можно больше простоты использования. Лямбды предназначены для этого. Предложение @AndyG полезно - для лямбда-ов реализация ProcessingForAllFormats должна быть разной. Но я понятия не имею, достаточно ли мощны лямбда-шаблоны в C++14/17 для создания такого API.
2 ответа
Как насчет упаковки универсальной лямбды с интерфейсом, ограниченным вашими желаемыми типами:
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
}
Делать это с лямбдой звучит как большая боль, так как это не закрытие, которое генерируется из шаблона, это operator()
, Это намного проще с шаблоном функтора:
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 <Format F>
struct Processor {
void operator() (SomeData<F> data) { /*...*/ }
};
int main() {
auto processing = ProcessingForAllFormats<Processor>{};
}