1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
|
#include <iostream>
using namespace std;
template <char I> struct index { };
template <char I, char J> struct marker;
// simple class with just a 2 element int array
struct A {
A() { }
A(int i, int j) { a[0] = i; a[1] = j; }
A(const A& x) { a[0] = x(0); a[1] = x(1); }
template<char I, char J>
marker<I,J> operator()(const index<I>&, const index<J>&) {
return marker<I,J>(*this);
}
friend std::ostream& operator<<(std::ostream& os, const A& x) {
return os << '{' << x.a[0] << ',' << x.a[1] << '}';
}
int& operator()(int i) { return a[i]; }
const int& operator()(int i) const { return a[i]; }
private:
int a[2];
};
template <char I, char J>
struct marker {
const int DI;
const int DJ;
marker(A& a) : myA(a), DI(1), DJ(0) { }
marker(A& a, const int i, const int j) : myA(a), DI(i), DJ(j) { }
marker(const marker& m) : myA(m.myA), DI(m.DI), DJ(m.DJ) { }
// cast I,J => J,I
operator marker<J,I>() const {
return marker<J,I>(myA,DJ,DI);
}
marker& operator=(const marker& m) {
myA(0) = m(0);
myA(1) = m(1);
return *this;
}
// returns the i'th or (1-i)'th element of myA
int operator()(int i) const {
return myA(i*DI + (1-i)*DJ);
}
// collects addition arguments
template<class LHS, class RHS>
struct add {
const LHS& lhs;
const RHS& rhs;
add(const LHS& l, const RHS& r) : lhs(l), rhs(r) { }
// actually does the adding recursively
int operator()(int i) const {
return lhs(i) + rhs(i);
}
add< add,marker > operator+(const marker& b) const {
return add< add,marker >(*this,b);
}
};
add< marker,marker > operator+(const marker& b) const {
return add< marker,marker >(*this,b);
}
template <class LHS, class RHS>
void operator=(const add< LHS, RHS>& expr) {
myA(0) = expr(0);
myA(1) = expr(1);
}
private:
A& myA;
};
int main() {
index<'i'> i;
index<'j'> j;
A a(1,2), b;
b(i,j) = a(j,i);
cout << b << endl; // "{2,1}"
b(i,j) = a(i,j) + a(j,i);
cout << b << endl; // "{3,3}"
b(i,j) = (marker<'i','j'>) a(j,i) + a(i,j); // OK if explicitly type-cast first argument
cout << b << endl; // "{3,3}"
b(i,j) = a(j,i) + a(i,j); // Fails to compile.
cout << b << endl; // expecting "{3,3}"
return 0;
}
|