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

C++ - create a bucket of instantiations for any lambda

我想在一处创建多个 templated-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 就像它是 library/API 的一部分一样,我希望给 "liblary" 的用户尽可能多的易用性如我所能。 Lambda 旨在提供这一点。 @AndyG 的建议很有用 - 对于 lambdas ProcessingForAllFormats 实现必须不同。但我不知道 C++14/17 中的 lambda 模板是否强大到足以构建这样的 API.

使用 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 与接口限制为所需类型:

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
}