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 注意到的那样 - 使用仿函数确实更容易实现,但更难使用。我对待 Format
、SomeData
和 ProcessingForAllFormats
就像它是 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
}
我想在一处创建多个 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 注意到的那样 - 使用仿函数确实更容易实现,但更难使用。我对待 Format
、SomeData
和 ProcessingForAllFormats
就像它是 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
}