2017-01-16 10 views
2

Я хочу создать несколько экземпляров шаблонов-лямбда в одном месте. Количество экземпляров и параметров каждого из них известно во время компиляции, поэтому я предполагаю, что это возможно. Это общая иллюстрация того, что я хочу сделать: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. И я знаю, что это было бы легко, если бы я использовал динамический полиморфизм вместо статического, но производительность в этом случае много для меня.

EDIT:

Как TartanLlama заметил - с помощью функторов действительно проще в реализации, но гораздо сложнее в использовании. Я отношусь к Format, SomeData и ProcessingForAllFormats, как если бы это была часть библиотеки/API, и я хочу дать пользователю этого «liblary» как можно большую удобство использования. Lambdas предназначены для этого. @ Исправление AndyG полезно - для lambdas реализация ProcessingForAllFormats должна быть разной. Но у меня нет идеи, если лямбда-шаблоны в C++ 14/17 достаточно мощны для создания такого API.

+0

примечание стороны: вы должны перейти от шаблона TypeName в шаблон класса, иначе вы будете запускать педантичные предупреждения в некоторых компиляторах ... –

ответ

1

Как насчет обертывание родовой лямбды с интерфейсом ограничена для все желаемых типов:

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 
} 
+0

Этот ответ интересный. Я должен найти способ изменить 'auto data' на' SomeData data' в мое свободное время. – jaskmar

+0

@jaskmar это невозможно. –

+0

К сожалению, он работает только с включенным 'concept lite', который не является частью стандарта. Это меня огорчает. – jaskmar

2

Выполнение этого с помощью лямбды звучит как большая боль, поскольку это не закрытие, которое создается из шаблона, это 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>{}; 
} 
+0

Я согласен с этим ответом. На самом деле никто не создает «экземпляры» лямбды. У них нет конструкторов по умолчанию. – AndyG

+0

Я согласен с вами, парни. Но, пожалуйста, взгляните на EDIT – jaskmar

 Смежные вопросы

  • Нет связанных вопросов^_^