使用Lambda代替可索引的模板参数

时间:2019-03-19 17:00:56

标签: c++11 templates lambda

我有一个将可索引对象作为模板参数的方法,例如:

template <typename OBJ>
int foo(int n, OBJ o)
{
  int x = 0;
  for (int i = 0; i < n; ++i) {
    x += o[i];
  }
  return x;
}

有没有一种方法可以为o参数传递一个lambda函数?换句话说,是否可以通过[]运算符而不是()运算符来调用lambda?

4 个答案:

答案 0 :(得分:4)

template<class F>
struct square_bracket_invoke_t {
  F f;
  template<class T>
  auto operator[](T&& t)const
  -> typename std::result_of< F const&(T&&) >::type
  { return f(std::forward<T>(t)); }
};
template<class F>
square_bracket_invoke_t< typename std::decay<F>::type >
make_square_bracket_invoke( F&& f ) {
  return {std::forward<F>(f)};
}

Live example

代码是C ++ 11,基本开销为零。

int main() {
  std::cout << foo( 6, make_square_bracket_invoke([](int x){ return x; } ) ) << "\n";
}

结果是0 + 1 + 2 + 3 + 4 + 5,也就是15。

这是个好主意吗?也许。但是为什么要停在那里?

为了最大程度的娱乐:

const auto idx_is = make_square_bracket_invoke([](auto&&f){return make_square_bracket_invoke(decltype(f)(f));});
int main() {
  std::cout << foo( 6, idx_is[[](int x){ return x; }] ) << "\n";
}

答案 1 :(得分:2)

您可以通过以下方式实现:

  1. 创建定义了operator[]的类模板,仿函数。
  2. 根据operator[]的{​​{1}}实施operator()
  3. 将lambda存储在包装的std::function中,作为类模板的成员变量。

这是一个演示程序。

std::function

及其输出

#include <iostream>
#include <functional>

template <typename OBJ>
int foo(int n, OBJ o)
{
  int x = 0;
  for (int i = 0; i < n; ++i) {
    x += o[i];
  }
  return x;
}

template <typename> struct Functor;

template <typename R> struct Functor<R(int)>
{
   using ftype = std::function<R(int)>;
   Functor(ftype f) : f_(f) {}

   R operator[](int i) const { return f_(i); }

   ftype f_;
};

int main()
{
   Functor<int(int)> f = {[](int i) -> int {return i*i;}};
   std::cout << foo(10, f) << std::endl;
}

Live demo

PS

285 在这里不合适。它不会使函数调用运算符过载。我怀疑还有一个更合适的名称。

答案 2 :(得分:1)

好吧,如果有帮助的话,这是一种将包装类的dest_port转发到lambda的operator[]的方法。

operator()

我经常使用这样的包装器。它们很方便,并且似乎没有任何计算开销,至少在由GCC编译时。您可以为template<class F> struct SubscriptWrapper_t { F f_; template<class T> auto operator[](T const& t_) const -> decltype(f_(t_)) { return f_(t_); } }; template<class F> SubscriptWrapper_t<typename std::decay<F>::type> SubscriptWrapper(F&& f_) { return{std::forward<F>(f_)}; } 做一个,甚至可以为at做一个。

编辑:已针对C ++ 11更新(并已更新为能够返回引用)

答案 3 :(得分:0)

可以执行此操作的包装类型的草图。

template<typename UnaryFunction>
class index_wrapper
{
public:
    index_wrapper(UnaryFunction func) : func(std::move(func)) {}

    template<typename T>
    std::invoke_result_t<UnaryFunction, T> operator[](T&& t)
    { return func(std::forward<T>(t)); }

private:
    UnaryFunction func;
};

随用法

#include <iostream>

template <typename OBJ>
int foo(int n, OBJ o)
{
  int x = 0;
  for (int i = 0; i < n; ++i) {
    x += o[i];
  }
  return x;
}

int main()
{
  index_wrapper f([](int i) -> int { return i*i; });
  std::cout << foo(10, f) << std::endl;
}

您可能希望将其限制为单个参数类型,以便可以提供类似于std::vector::reference等的成员类型别名。