C++ - 为任何 lambda 创建一个实例化桶

Posted

技术标签:

【中文标题】C++ - 为任何 lambda 创建一个实例化桶【英文标题】:C++ - create a bucket of instantiations for any lambda 【发布时间】:2017-01-16 15:38:29 【问题描述】:

我想在一个地方创建几个模板化 lambda 实例。每个实例化的数量和参数在编译时是已知的,所以我认为这是可能的。这是我想要做的一般说明:

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 所注意到的 - 使用仿函数确实更容易实现,但更难使用。我对待FormatSomeDataProcessingForAllFormats 就像它是库/API 的一部分一样,我希望尽可能地为该“库”的用户提供易用性。 Lambda 旨在提供这一点。 @AndyG 的建议很有用——对于 lambda,ProcessingForAllFormats 的实现必须不同。但我不知道 C++14/17 中的 lambda 模板是否强大到足以构建这样的 API。

【问题讨论】:

旁注:你应该从 template 类型名切换到 template 类,否则你会在某些编译器中触发迂腐警告... 【参考方案1】:

使用 lambda 执行此操作听起来很痛苦,因为它不是从模板生成的闭包,而是 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>;

【讨论】:

我同意这个答案。一个并没有真正创建 lambda 的“实例”。它们没有默认构造函数。 我同意你们的观点。但请看一下编辑【参考方案2】:

如何使用限制为所需类型的接口包装泛型 lambda:

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

【讨论】:

这个答案很有趣。我应该在空闲时间找到将auto data 更改为SomeData&lt;auto&gt; data 的方法。 @jaskmar 但这是不可能的。 不幸的是,它只适用于concepts lite,这不是标准的一部分。这让我很难过。

以上是关于C++ - 为任何 lambda 创建一个实例化桶的主要内容,如果未能解决你的问题,请参考以下文章

C++ lambda表达式总结

C++ lambda表达式(函数指针和function)

C++ lambda 表达式的生命周期是多少?

QTimer::singleShot 仅在间隔为 0 时调用 lambda

C++ std::function怎么用

构造函数用于创建类的实例对象,构造函数名应与类名相同,返回类型为void.