使用std :: greater或std :: less作为参数的参数

Qaz*_*Qaz 13 c++ functor comparison-operators c++11

我想用一个接受任一参数std::greater<int>std::less<int>作为参数的参数来创建一个函数.不过,我仍然坚持参数的语法.

这是我尝试的格式:

myFunction(int a, int b, bool *comp(int, int)) { … }
…
std::greater<int> bigger;
myFunction(2, 3, bigger);
Run Code Online (Sandbox Code Playgroud)

但这不起作用,我怀疑第三个参数完全错误.它到底应该是什么?

无法转换std::greater<int>bool* (*)(int, int)

use*_*027 15

采用比较器的函数通常通过模板实现:

template <typename Comparator>
myFunction(int a, int b, Comparator comp) { … }
Run Code Online (Sandbox Code Playgroud)

但你也可以std::function用来实现它:

myFunction(int a, int b, std::function<bool (int, int)> ) { … }
Run Code Online (Sandbox Code Playgroud)

第一个版本公开了标题中的代码,但通常会表现得更好.对于第二个版本,您可以隐藏.cpp文件中的实现,但由于无法内联比较器调用,您将失去一些性能.


Yak*_*ont 8

因此,这里的技巧是,std::lessstd::greater实际上可以平凡无状态构造函数对象.但是它们不支持转换为函数指针.

有效的选择是(A)通过template参数获取比较器并在头中实现代码:

template<typename C> void myFunc( int a, int b, C comp )
Run Code Online (Sandbox Code Playgroud)

这意味着你必须在头文件中实现它,或者(B)通过以下方式键入擦除函数对象std::function< bool(int, int) >:

void myFunc( int a, int b, std::function< bool(int, int) > comp )
Run Code Online (Sandbox Code Playgroud)

这有一些成本(可能很重要?Profile!)(通过对无状态std less /更大的小对象优化来避免堆分配,但virtual无论如何都会花费函数调用,这也会阻止内联).

或者(C)编写一些代码,让您使用无状态仿函数并将其转换为函数指针:

template<typename T>
using Type = T;
template<typename StatelessFunctor>
struct function_ptr_of_stateless_t {
  template<typename R, typename... Args>
  operator Type<R(Args...)>*() const {
    return [](Args... args)->R {
     return StatelessFunctor()(std::forward<Args>(args)...);
    };
  }
};
template<typename StatelessFunctor>
function_ptr_of_stateless_t<StatelessFunctor> as_function_ptr() {
  return {};
}

bool myFunction( int a, int b, bool(*comp)(int, int) ) { return comp(a,b); }
int main() {
  std::cout << myFunction(3,7, as_function_ptr<std::less<int>>() ) << "\n";
}
Run Code Online (Sandbox Code Playgroud)

template功能as_function_ptr需要你的无国籍仿函数的类型,并创建一个扔掉类型,可以让你将它转换为任何兼容的函数指针类型.

这比std::function解决方案的开销要小得多,因为对函数指针的调用往往比virtual方法更快,而且一些编译器(如gcc)在内联函数指针方面相当不错,甚至从一个编译单元到另一个编译单元.

作为奖励,在C++ 14中你可以使用:

int main() {
  std::cout << myFunction(3,7, as_function_ptr<std::less<>>() ) << "\n";
}
Run Code Online (Sandbox Code Playgroud)

它仍然可以很好地工作.