在C++中将运算符作为参数传递

3
我有两个变量和一个运算符(可以是+、-、/、比较等)。 编写一个函数,将这两个变量和运算符作为参数传递进去,这样做是否明智? 该函数可能如下所示:

function calculate(num1, num2, operator) { // function body }

T foo(int a,int b, sometype(not sure) operator)

然后将其转换为字符串。
foo(a,b,+);

as  a+b

这是一个好的方法吗?还有其他方法吗?

1
你想要做什么? - MikeCAT
你可以使用lambda表达式,例如:foo(a, b, [](int x, int y) { return x + y;}); - W.F.
有没有办法将运算符作为参数发送,然后将其用于发送的参数? - user2256825
但是我需要为每个运算符拥有大量的 Lambda 函数,不是吗? - user2256825
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - user2256825
显示剩余4条评论
2个回答

11
你无法这样做。运算符是特殊的,它们不是普通函数。(例如,运算符可以进行短路求值,并且如果所有操作数都是内置类型,则没有重载解析。函数不能做到这一点。)
相反,传递一个二元操作对象,如下所示:
template <class BinaryOp>
int fun(int, int, BinaryOP);

你可以将像 std::plus<> 的函数对象或二元lambda作为第三个参数传递。这在C++中是一种常见的做法。
请注意,封装内置运算符的函数对象,例如前面提到的 std::plus,可在头文件<functional>中轻松获得。
参考示例代码:
#include <iostream>
#include <functional>

template <class T>
void fun (int i, int j, T t)  {
    std::cout << t(i,j) << "\n";
}

int main () {
    fun(1,2,std::plus<>{});                      // Or std::plus<int>{} in C++11
    fun(1,2,[](auto i, auto j){return i * j;});  // Again, with explicit types for C++11
}

这将打印出:

3
2

由于此处标记为C++11:本回答中使用的函数对象std::plus<T=void>等仅在C++14及以上版本中可用。在C++11中,您需要提供一个模板参数,例如std::plus<int>。同样适用于lambda表达式,需要变为[](int i, int j){...}


你能否也提供一份二进制lambda的示例代码?这似乎是非常高级的东西。 - user2256825
@user2256825 完成。再次提醒,如果是C++11,您需要明确指定类型。 - Baum mit Augen

4

运算符不能以这种方式传递,否则它不会编译:该语言不允许这样做。您可以传递一个描述要执行的操作的字符:

template <class T>
T foo(T lhs, T rhs, char op)
{
   switch (op)
   {
       case '+':
                return lhs + rhs;

       // other operators

   }
}

另一个选项是将实际计算完成的函数作为参数传递:

template <class T, class Operator>
T foo(T lhs, T rhs, Operator op)
{
    return op(lhs, rhs);
}

现在你可以编写自己的Operator,或者使用已经提供的std::plusstd::minus等。你可以在<functional>中找到它们。
// ...
foo(5, 10, std::plus<int>{})

如果您想要自己的版本,请编写所需的可调用项作为lambda函数或函数:

template <class T>
T add(T lhs, T rhs) { return lhs + rhs; }

foo(5, 10, add<int>);
foo(5, 10, [](int a, int b){ return a + b; }); // or use `auto` to make it generic

1
有下投票的原因吗? - edmz
最简单的选择是传递一个字符。 - Barry
@Barry 语法错误?请随意编辑,感激不尽。否则,您觉得这不是最简单的方法吗? - edmz
手写调度表基于开关(char或其他)不容易正确实现:事实上,根据我多年来遇到的错误数量,它们极易出错。它们也很难维护;如果您在代码中使用类似上述技术的多个位置,当您添加另一个运算符时,跟踪和修复所有这些位置将需要时间和注意力,编译器一点也不会帮助您。 "容易",因为大一学生可能会将其作为“解决方案”,但不是“最终减少工作量”的“容易”。 - Yakk - Adam Nevraumont
1
@Yakk 我稍微编辑了一下。不过,如果不简单的话,这是我能想到的第一件事情。模板并不容易维护,如果你犯了错误,编译器会盲目地对你进行扩展,更不用说对于长期的解决方案,你需要对可调用对象应用一些约束。我必须要知道模板、SFINAE/Concepts来解决原始问题吗?无论如何,我认为这不是downvoting的理由。 - edmz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接