例如,我有以下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 ++的等价物是什么?
答案 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);