#include <type_traits>
#include <utility>
//used for inheriting from same type twice
template<class sub_expr>
class inherit_again : public sub_expr {
public:
inherit_again(sub_expr rhs) : sub_expr(std::move(rhs)) {}
};
//used for SFINAE (no duck typing here)
class expression_part {
protected:
expression_part() {}
expression_part(const expression_part&) {}
expression_part& operator=(const expression_part&) {return *this;}
~expression_part() {}
};
//used for parameter values
class expression_parameter : private expression_part {
public:
expression_parameter& operator&&(const expression_parameter&) {return *this;} //ignored
expression_parameter& operator,(const expression_parameter&) {return *this;} //ignored
template<class T>
const T& operator()(const T& v) const {return v;}
};
//used for constants
template<class V>
class expression_constant : private expression_part {
V v;
public:
expression_constant& operator&&(const expression_parameter&) {return *this;} //ignored
expression_parameter& operator,(const expression_parameter&) {return *this;} //ignored
expression_constant(V v_) :v(std::move(v_)) {}
template<class T>
V operator()(const T&) const {return v;}
};
template<class U>
expression_constant<U> expr_const(U u) {return expression_constant<U>(std::move(u));}
//used for addition
template<class lhs, class rhs_given>
class expression_add :private lhs, private inherit_again<rhs_given> {
typedef inherit_again<rhs_given> rhs;
public:
expression_add& operator&&(const expression_parameter&) {return *this;} //ignored
expression_add& operator,(const expression_parameter&) {return *this;} //ignored
expression_add(lhs l, rhs_given r):lhs(std::move(l)), rhs(std::move(r)) {}
template<class T>
auto operator()(const T& v) const -> decltype(lhs::operator()(v)+rhs::operator()(v)) {return lhs::operator()(v)+rhs::operator()(v);}
};
template<class lhsexpr, class rhsexpr>
auto operator+(lhsexpr lhs, rhsexpr rhs) -> typename std::enable_if<
std::is_base_of<expression_part, lhsexpr>::value &&
std::is_base_of<expression_part, rhsexpr>::value,
expression_add<lhsexpr, rhsexpr>>::type
{return expression_add<lhsexpr, rhsexpr>(std::move(lhs), std::move(rhs));}
template<class lhsexpr, class rhsexpr>
auto operator+(lhsexpr lhs, rhsexpr rhs) -> typename std::enable_if<
std::is_base_of<expression_part, lhsexpr>::value &&
!std::is_base_of<expression_part, rhsexpr>::value,
expression_add<lhsexpr, expression_constant<rhsexpr>>>::type
{return expression_add<lhsexpr, expression_constant<rhsexpr>>(std::move(lhs), expression_constant<rhsexpr>(std::move(rhs)));}
template<class lhsexpr, class rhsexpr>
auto operator+(lhsexpr lhs, rhsexpr rhs) -> typename std::enable_if<
!std::is_base_of<expression_part, lhsexpr>::value &&
std::is_base_of<expression_part, rhsexpr>::value,
expression_add<expression_constant<lhsexpr>, rhsexpr>>::type
{return expression_add<expression_constant<lhsexpr>, rhsexpr>(expression_constant<lhsexpr>(std::move(lhs)), std::move(rhs));}
//used for multiplication
template<class lhs, class rhs_given>
class expression_multiply :private lhs, private inherit_again<rhs_given> {
typedef inherit_again<rhs_given> rhs;
public:
expression_multiply& operator&&(const expression_parameter&) {return *this;} //ignored
expression_multiply& operator,(const expression_parameter&) {return *this;} //ignored
expression_multiply(lhs l, rhs_given r):lhs(std::move(l)), rhs(std::move(r)) {}
template<class T>
auto operator()(const T& v) const -> decltype(lhs::operator()(v)*rhs::operator()(v)) {return lhs::operator()(v)*rhs::operator()(v);}
};
template<class lhsexpr, class rhsexpr>
auto operator*(lhsexpr lhs, rhsexpr rhs) -> typename std::enable_if<
std::is_base_of<expression_part, lhsexpr>::value &&
std::is_base_of<expression_part, rhsexpr>::value,
expression_multiply<lhsexpr, rhsexpr>>::type
{return expression_multiply<lhsexpr, rhsexpr>(std::move(lhs), std::move(rhs));}
template<class lhsexpr, class rhsexpr>
auto operator*(lhsexpr lhs, rhsexpr rhs) -> typename std::enable_if<
std::is_base_of<expression_part, lhsexpr>::value &&
!std::is_base_of<expression_part, rhsexpr>::value,
expression_multiply<lhsexpr, expression_constant<rhsexpr>>>::type
{return expression_multiply<lhsexpr, expression_constant<rhsexpr>>(std::move(lhs), expression_constant<rhsexpr>(std::move(rhs)));}
template<class lhsexpr, class rhsexpr>
auto operator*(lhsexpr lhs, rhsexpr rhs) -> typename std::enable_if<
!std::is_base_of<expression_part, lhsexpr>::value &&
std::is_base_of<expression_part, rhsexpr>::value,
expression_multiply<expression_constant<lhsexpr>, rhsexpr>>::type
{return expression_multiply<expression_constant<lhsexpr>, rhsexpr>(expression_constant<lhsexpr>(std::move(lhs)), std::move(rhs));}
template<class lhsexpr, class container>
typename std::enable_if<std::is_base_of<expression_part, lhsexpr>::value, lhsexpr>::type
operator||(lhsexpr lhs, container& rhs)
{
for(auto it=rhs.begin(); it!=rhs.end(); ++it)
*it = lhs(*it);
return lhs;
}
expression_parameter x;
#include <vector>
#include <iostream>
#define take
#define with &&
#define in ||
int main() {
std::vector<int> container0;
container0.push_back(-4);
container0.push_back(0);
container0.push_back(3);
take x*x with x in container0; //here's the magic line
for(auto it=container0.begin(); it!=container0.end(); ++it)
std::cout << *it << ' ';
std::cout << '\n';
std::vector<double> container1;
container1.push_back(-4.4);
container1.push_back(0);
container1.push_back(3.3);
take 1+x with x in container1; //here's the magic line
for(auto it=container1.begin(); it!=container1.end(); ++it)
std::cout << *it << ' ';
std::cout << '\n';
auto a = x+x*x+'a'*x;
auto b = a; //make sure copies work
b in container0;
b in container1;
std::cout << sizeof(b);
return 0;
}