什么是java.util.function.Consumer的C ++等价物?

时间:2016-08-03 03:21:07

标签: java c++

例如,我有以下Java代码:

import java.util.function.Consumer;

public class Main {
  public static void main(String[] args) {
    Consumer<String> c = (x) -> System.out.println(x.toLowerCase());
    c.accept("Java2s.com");
  }
}

C ++的等价物是什么?

4 个答案:

答案 0 :(得分:4)

使用std::function<void(const std::string&)>

您可以从函数指针或lambda中初始化this的实例,例如:

void foo(const std::string &s) {
    std::cout << s << std::endl;
}

// later
std::function<void(const std::string &)> c = foo;
c("Java2s.com");

std::function<void(const std::string &)> c = [](const std::string &) {
    std::cout << s << std::endl;
};
c("Java2s.com");

答案 1 :(得分:1)

如果你真的想念accept。你也可以实现:

#include <functional>
#include <iostream>
#include <string>

template <class Food>
class Consumer {
 private:
  std::function<void(Food)> consume_;

 public:
  template <class Eater>
  Consumer<Food>(Eater consume) : consume_(consume){};

  void accept(Food food) { consume_(food); }
};

// Usage
int main() {
  Consumer<const std::string&> consumer([](
      const std::string& out) { std::cout << out << '\n'; });
  consumer.accept("My lovley string.");
  consumer.accept("Will be eaten!");
}

或者你甚至可以:

template <class Food>
class Consumer {
 public:
  std::function<void(Food)> accept;

  template <class Eater>
  Consumer<Food>(Eater consume) : accept(consume){};
};

如果您希望能够动态更换accept

换句话说,我不明白为什么消费者存在于Java中。

答案 2 :(得分:1)

让我们首先看一下如何在Java中使用Consumer的更完整示例。例如,要打印树中的节点,我们可能会有类似code from CodeReview.se

的内容
import java.util.function.Consumer;

public static void preOrderTraversal(TreeViewItem treeNode,               
                                     Consumer<TreeViewItem> action) {
    action.accept(treeNode);
    for (TreeViewItem child : treeNode.getItems()) {
        preOrderTraversal(child, action);
    }
}

// Call that code with
preOrderTraversal(rootNode, (TreeViewItem node) -> System.out.println(node.getText()));

在C ++中,有少数人使用std::function来做这件事,但至少在我看来这通常是个错误。相反,通常应该利用C ++的模板工具比Java泛型更通用的事实,因此我们可以使用Consumer的模板参数。

除此之外,我们通常会利用C ++支持运算符重载的事实,因此当我们想要传递一个像函数一样的东西时,我们可以(并且确实)通常使用函数调用语法来调用那个类似函数的东西(可能是指向函数的指针,或者来自lambda的闭包等):

template <class Item, class Consumer>
void preOrderTraverse(Item i, Consumer action) { 
    action(item);
    for (auto & child : item->getChildren())
        preOrderTraverse(child, action);
}

与Java代码非常相似,我们可以使用lambda表达式定义动作:

preOrderTraverse(rootNode, [](auto node) { std::cout << node->getText(); });

作为一个简单的经验法则,假设在C ++中对参数类型(至少对非虚函数 1 )使用std::function是错误的。对于这种情况,应该将类型作为模板参数传递。 std::function通常会被保留用于(例如)我们需要接受一些类似函数的对象,存储它并稍后调用它的情况。参数类型仍应是模板参数,但我们存储它的对象可以合理地为std::function

1.由于虚函数不能作为模板,如果你需要将这样的泛型函数传递给必须是虚函数的函数,那么几乎唯一真正的选择就是使用std::function(或产生你自己的类似的东西,这不太可能是一个真正的改进)。 功能

答案 3 :(得分:0)

我冒昧地猜测您需要的功能是基于 lambda表达式提供的功能。

C ++ 11提供对lambda表达式的支持,以下代码在更通用的级别上提供了您发布的代码。

auto algorithm = [&]( double x, double m, double b ) -> double
   {
   return m*x+b;
   };

int a=algorithm(1,2,3), b=algorithm(4,5,6);