Overloading functions and methods for CLEF arguments

Overloading functions

Given a function, it is possible to overload it for CLEF expression arguments, returning a CLEF expression using the CLEF_MAKE_FNT_LAZY macro.

Synopsis

namespace triqs { namespace clef {
CLEF_MAKE_FNT_LAZY (function_to_make_lazy);
}}

For example:

#include <nda/clef.hpp>
#include <iostream>

// a simple foo function
double foo(double x) { return x / 2; }
int foo(int x) { return x * 2; }

// a more complex case : bar is already a template
// we have to disable it for CLEF expression to avoid ambiguity

// C++14 clean syntax will be (using concepts)
// template<NotClefExpression T>
// T bar (T const & x) { return x+1;}

// C++11 workaround
template <typename T> typename std::enable_if<!nda::clef::is_clef_expression<T>, T>::type bar(T const &x) { return x + 1; }

namespace nda::clef {
  using ::foo;
  CLEF_MAKE_FNT_LAZY(foo);

  using ::bar;
  CLEF_MAKE_FNT_LAZY(bar);
} // namespace nda

int main() {
  nda::clef::placeholder<3> x_;
  std::cout << foo(2.0) << " " << eval(x_ + foo(x_), x_ = 3) << " " << eval(x_ + foo(x_), x_ = 3.5) << std::endl;
  std::cout << bar(2.0) << " " << eval(x_ + bar(x_), x_ = 3) << " " << eval(x_ + bar(x_), x_ = 3.5) << std::endl;
}
1 9 5.25
3 7 8

Note that:

  • This overload must be defined in the nda::clef namespace, since it is found by ADL.

  • The function foo can have many overloads.

  • The function bar can be a template, BUT then the template must be disabled for lazy expressions.

  • The overload is already defined by clef for usual functions:

#include <nda/clef.hpp>
#include <iostream>
int main() {
  nda::clef::placeholder<3> x_;
  std::cout << 2.0 + std::cos(2.0) << std::endl;
  std::cout << eval(x_ + cos(x_), x_ = 2) << std::endl; // NB : note the absence of std::
}
1.58385
1.58385

Overloading operator() and other methods

Similarly to functions, classes can define an operator() for CLEF expressions arguments (or any other method). It is an ordinary operator() that must:

  • Be enabled only when one argument is a CLEF expression

  • Return a CLEF expression.

Example:

#include <nda/clef.hpp>
#include <iostream>

struct Obj {
  double v;                  // put something in it
  Obj(double v_) : v(v_) {}  // constructor
  Obj(Obj const &) = delete; // a non copyable object, to illustrate that we do NOT copy...

  // The "normal", non CLEF call operator ....
  double operator()(double x) const { return 10 * x; }

  // This macro implements properly an overload of the operator ()
  CLEF_IMPLEMENT_LAZY_CALL();

  // a method
  double my_method(double x) const { return 2 * x; }

  // CLEF overload
  // WARNING : the method MUST be const
  CLEF_IMPLEMENT_LAZY_METHOD(Obj, my_method);

  // Just to print itself nicely in the expressions
  friend std::ostream &operator<<(std::ostream &out, Obj const &x) { return out << "Obj"; }
};

int main() {
  Obj f(7);
  nda::clef::placeholder<1> x_;
  nda::clef::placeholder<2> y_;

  std::cout << "Clef expression     : " << f(y_) + 2 * x_ << std::endl;
  std::cout << "Complete evaluation : " << eval(f(x_) + 2 * x_, x_ = 1) << std::endl;
  std::cout << "Partial evaluation  : " << eval(f(y_) + 2 * x_, y_ = 1) << std::endl;
  std::cout << "Complete evalution  : " << eval(f(y_) + 2 * x_, x_ = 3, y_ = 1) << std::endl << std::endl;

  std::cout << "Clef expression     : " << f.my_method(y_) + 2 * x_ << std::endl;
  std::cout << "Complete evaluation : " << eval(f.my_method(x_) + 2 * x_, x_ = 1) << std::endl;
  std::cout << "Partial evaluation  : " << eval(f.my_method(y_) + 2 * x_, y_ = 1) << std::endl;
  std::cout << "Complete evalution  : " << eval(f.my_method(y_) + 2 * x_, x_ = 3, y_ = 1) << std::endl;
}
Clef expression     : (lambda(_2) + (2 * _1))
Complete evaluation : 12
Partial evaluation  : (10 + (2 * _1))
Complete evalution  : 16

Clef expression     : (lambda(Obj, _2) + (2 * _1))
Complete evaluation : 4
Partial evaluation  : (2 + (2 * _1))
Complete evalution  : 8
NB When the method or the non CLEF operator() is already a template,

it must be disabled for clef expression argument, using the trait

clef::is_clef_expression<T...> // true iif one of the T is a clef expression

as the bar function above.