A post by Yakk alerted me to the idea of named operators in C++. This look splendid (albeit very unorthodox). For instance, the following code can be made to compile trivially:
vector<int> vec{ 1, 2, 3 };
cout << "3 in " << vec << ": " << (3 <in> vec) << '\n'
<< "5 in " << vec << ": " << (5 <in> vec) << '\n';
Of course the whole thing has to be generic so any binary function-like thing can be used to define operators, e.g.
auto in = make_named_operator(
[](int i, vector<int> const& x) {
return find(begin(x), end(x), i) != end(x);
});
I’d like to know whether the following implementation is sufficient to handle all “interesting”1 cases, and whether it’s robust. For instance, I’m storing the operands in references. That should work since they’re only stored until after the expression has completed, and thus should never go stale. I’m especially interested in feedback on the return types of the operator functions below and on the design rationale of using the <…> syntax for named operators.2
It seems to handle templates as well as a mixture of different types (and cv-qualification).
#include <utility>
template <typename F>
struct named_operator_wrapper {
F f;
};
template <typename T, typename F>
struct named_operator_lhs {
F f;
T& value;
};
template <typename T, typename F>
inline named_operator_lhs<T, F> operator <(T& lhs, named_operator_wrapper<F> rhs) {
return {rhs.f, lhs};
}
template <typename T, typename F>
inline named_operator_lhs<T const, F> operator <(T const& lhs, named_operator_wrapper<F> rhs) {
return {rhs.f, lhs};
}
template <typename T1, typename T2, typename F>
inline auto operator >(named_operator_lhs<T1, F> const& lhs, T2 const& rhs)
-> decltype(lhs.f(std::declval<T1>(), std::declval<T2>()))
{
return lhs.f(lhs.value, rhs);
}
template <typename T1, typename T2, typename F>
inline auto operator >=(named_operator_lhs<T1, F> const& lhs, T2 const& rhs)
-> decltype(lhs.value = lhs.f(std::declval<T1>(), std::declval<T2>()))
{
return lhs.value = lhs.f(lhs.value, rhs);
}
template <typename F>
inline constexpr named_operator_wrapper<F> make_named_operator(F f) {
return {f};
}
For the interested, a full example implementation is on GitHub.
1 <insert your definition of “interesting” here>
2 I considered other alternatives, such as %…% which is used by R, and allowing different operators (as done by Yakk) to allow for different operator precedences but I decided against that because I think it makes operator precedence even more complicated than it already is in C++.
<tothepowerof>operator – Bartek Banachewicz Feb 26 at 18:25