Select 一元与二进制 std::transform 根据可调用对象的签名自动重载函数
Select unary vs. binary std::transform function overload automatically based on callable's signature
std::transform 提供采用一元(一个参数)或二元(两个参数)可调用操作(通常是 lambda)的重载。
我想将我想要的可调用对象作为参数传递给父函数,并使用编译时(例如模板元编程)方法自动 select std::transform
哪个重载获得使用,基于传递的可调用对象是否具有带有一个或两个参数的函数签名。
这是用(尚未工作)代码表示的所需方法:
#include <algorithm>
auto UnaryOp = [](const auto& src) { return src; }; // simple copy
auto BinaryOp = [](const auto& src1, const auto& src2) {return src1 + src2; }; // accumulate
auto GenericTransformer = [](auto src, auto dst, auto operation) { // operation is unary OR binary
/* unrelated code */
// need to chose this one:
std::transform(src.begin(), src.end(), dst.begin(), operation);
// or this one:
std::transform(src.begin(), src.end(), dst.begin(), dst.begin(), operation);
// depending on whether unary or binary operation is passed in 'operation' argument
/* unrelated code */
};
int main() {
std::vector<int> source_vec(100);
std::vector<int> dest_vec(100);
GenericTransformer(source_vec, dest_vec, UnaryOp); // i.e. copy source to destination
GenericTransformer(source_vec, dest_vec, BinaryOp); // i.e. accumulate source into destination
}
这里我定义了两个 lambda 运算——一个一元运算和一个二进制运算(UnaryOp
和 BinaryOp
)——它们从 main()
传递给 GenericTransformer()
。
在 GenericTransformer()
中,我可以使用什么编译时魔法来自动 select 根据 [=20= 的函数签名进行两个 std::transform()
调用中的哪一个] 争论?
注意:这是出于示例目的的简化案例。我宁愿不必将 GenericTransformer()
拆分为两个单独的函数(一个一元函数和一个二进制函数),因为这会导致此处未显示的大量代码重复。坚持 DRY 理念!
使用 C++17,您可以混合使用 if constexpr
和 std::is_invocable
:
if constexpr (std::is_invocable_v<
decltype(operation), decltype(*src.begin())>) {
std::transform(src.begin(), src.end(), dst.begin(), operation);
}
else {
std::transform(src.begin(), src.end(), dst.begin(), dst.begin(), operation);
}
您还可以检查 operation
在第二种情况下是否有效,但这需要额外的 else
分支以避免在(两个分支均无效)时消除编译时错误,并且这需要一些 .
std::transform 提供采用一元(一个参数)或二元(两个参数)可调用操作(通常是 lambda)的重载。
我想将我想要的可调用对象作为参数传递给父函数,并使用编译时(例如模板元编程)方法自动 select std::transform
哪个重载获得使用,基于传递的可调用对象是否具有带有一个或两个参数的函数签名。
这是用(尚未工作)代码表示的所需方法:
#include <algorithm>
auto UnaryOp = [](const auto& src) { return src; }; // simple copy
auto BinaryOp = [](const auto& src1, const auto& src2) {return src1 + src2; }; // accumulate
auto GenericTransformer = [](auto src, auto dst, auto operation) { // operation is unary OR binary
/* unrelated code */
// need to chose this one:
std::transform(src.begin(), src.end(), dst.begin(), operation);
// or this one:
std::transform(src.begin(), src.end(), dst.begin(), dst.begin(), operation);
// depending on whether unary or binary operation is passed in 'operation' argument
/* unrelated code */
};
int main() {
std::vector<int> source_vec(100);
std::vector<int> dest_vec(100);
GenericTransformer(source_vec, dest_vec, UnaryOp); // i.e. copy source to destination
GenericTransformer(source_vec, dest_vec, BinaryOp); // i.e. accumulate source into destination
}
这里我定义了两个 lambda 运算——一个一元运算和一个二进制运算(UnaryOp
和 BinaryOp
)——它们从 main()
传递给 GenericTransformer()
。
在 GenericTransformer()
中,我可以使用什么编译时魔法来自动 select 根据 [=20= 的函数签名进行两个 std::transform()
调用中的哪一个] 争论?
注意:这是出于示例目的的简化案例。我宁愿不必将 GenericTransformer()
拆分为两个单独的函数(一个一元函数和一个二进制函数),因为这会导致此处未显示的大量代码重复。坚持 DRY 理念!
使用 C++17,您可以混合使用 if constexpr
和 std::is_invocable
:
if constexpr (std::is_invocable_v<
decltype(operation), decltype(*src.begin())>) {
std::transform(src.begin(), src.end(), dst.begin(), operation);
}
else {
std::transform(src.begin(), src.end(), dst.begin(), dst.begin(), operation);
}
您还可以检查 operation
在第二种情况下是否有效,但这需要额外的 else
分支以避免在(两个分支均无效)时消除编译时错误,并且这需要一些