C++’s .* and ->* operators: Part 3

Well, none of my drafts are yet worth putting up (pre­view: the first part of a long series on col­or the­o­ry, and a fol­low-up to the aca­d­e­mic advis­ing epic dra­ma “I Am Now a Man­age­ment Major“), so here’s anoth­er filler post. I stopped being seri­ous since the first post, so enjoy the troll.

Wel­come back, and thanks for pick­ing up this April Fools’ issue of “@#$%ing Strange C++: I hate this lan­guage sooo much.” Today, let’s take our exam­ple code from last time and apply some text­book tech­niques to screw it u—improve its read­abil­i­ty and reusabil­i­ty.

Why would any­one do this with exam­ple code writ­ten to show an entire­ly awful con­cept with an entire­ly con­trived exam­ple? I don’t know.

Let’s backpedal to the impor­tant part: Vector3D. Hey, we named it Vector3D, so why does it only allow floats? Why doesn’t it do any vec­tor-y stuff? LET US ADD SOME FUNCTIONALITY WHICH WE WILL NOT USE.

// HELL YEAH, LET'S TEMPLATE IT
template<typename Component_T = double> // STICK IN A DEFAULT, EVEN IF IT DOESN'T MAKE SENSE
class Vector3D {
public:
	typedef Component_T ComponentType; // YOU'LL SEE WHY WE NEED THIS

	Component_T x;
	Component_T y;
	Component_T z;

	// Component_T MIGHT BE A BIGNUM CLASS OR SOMETHING, SO WE PASS CONST REFERENCES
	Vector3D(const Component_T &x, const Component_T &y, const Component_T &z) :
		x(x), y(y), z(z) {
	}

Mmm-hmm, tem­plates are a sure part of any messy C++ recipe. Once you learn them, you’ll nev­er remem­ber how to pro­gram well again. Let’s con­tin­ue on to the oper­a­tor over­loads. We com­plete­ly ignore the fact that infix nota­tion makes no sense in a lan­guage that fea­tures pre­fix for every­thing else, or that the­se are all real­ly con­struc­tors, so they’re bet­ter off as con­struc­tors in the “named con­struc­tors” idiom, or that nobody ever fol­lows the same con­ven­tions for the­se “arith­metic” oper­a­tors; we’re using them because they’re snazzy lit­tle bits of sug­ar coat­ing.

	// OPERATOR OVERLOADS ALL OVER THE PLACE
	friend Vector3D operator-(const Vector3D &a) {
		return Vector3D(-a.x, -a.y, -a.z);
	}

	friend Vector3D operator+(const Vector3D &a, const Vector3D &b) {
		return Vector3D(a.x + b.x, a.y + b.y, a.z + b.z);
	}

	friend Vector3D operator-(const Vector3D &a, const Vector3D &b) {
		return Vector3D(a.x - b.x, a.y - b.y, a.z - b.z);
	}

	// WE DON'T CARE THAT SOMETIMES PEOPLE WANT THE INNER (DOT) PRODUCT
	friend Vector3D operator*(const Vector3D &a, const Vector3D &b) {
		return Vector3D(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
	}

	friend Vector3D operator*(const Vector3D &a, const Component_T &s) {
		return Vector3D(a.x * s, a.y * s, a.z * s);
	}

	// LOLOL REDUNDANT
	friend Vector3D operator*(const Component_T &s, const Vector3D &a) {
		return Vector3D(a.x * s, a.y * s, a.z * s);
	}

	friend Vector3D operator/(const Vector3D &a, const Component_T &s) {
		return Vector3D(a.x / s, a.y / s, a.z / s);
	}

	// BECAUSE a.dot(b) IS LIKE THE OTHER OPERATORS, NOT BECAUSE INFIX IS GOOD
	Vector3D dot(const Vector3D &a) {
		return Vector3D(x * a.x, y * a.y, z * a.z);
	}

	friend std::ostream &operator<<(std::ostream &os, const Vector3D &v) {
		return os << '<' << v.x << ", " << v.y << ", " << v.z << '>';
	}
};

Alright, now that we have blinged out Vector3D for no appar­ent rea­son, let’s extend our Operation cla—oh crud, there’s unqual­i­fied types need­ing the typename key­word, tem­plate para­me­ters, and angled brack­ets all over the place. What to do? We’ll typedef every­thing away, of course.

template<typename Vector3D_T> // DAMN, NOW WE HAVE TO TEMPLATE THIS
class Operation: public std::binary_function<Vector3D_T, typename Vector3D_T::ComponentType, void> {
protected:
	// WE NEED typename TO FULLY QUALIFY; DON'T ASK WHY
	typedef typename Vector3D_T::ComponentType ComponentType;
	// (ROYAL) WE DON'T FEEL LIKE TYPING THESE ANY MORE
	typedef void (Operation::*OperationPointerType)(Vector3D_T &, const ComponentType &) const;
	typedef ComponentType Vector3D_T::*ComponentPointerType;

	// a pointer to a const member function with params (Vector3D &, float) returning void
	OperationPointerType operationPtr;
	// store the component selection using a member pointer
	ComponentPointerType componentPtr;

Just for the hell of it, let’s derive from std::binary_function to pol­lute our class name­space and let us do weird, fan­cy things with argu­ment bind­ing in <functional> and algo­rithms from <algorithm>, <numeric>, etc.

public:
	Operation(OperationPointerType const operationPtr, ComponentPointerType const componentPtr) :
		operationPtr(operationPtr), componentPtr(componentPtr) {
	}

	void setComponent(ComponentPointerType const componentPtr) {
		this-&gt;componentPtr = componentPtr;
	}

	void setOperation(OperationPointerType const operation) {
		this-&gt;operationPtr = operation;
	}

I guess it’s a lit­tle bet­ter with the typedefs. But here we go with the operator() over­load that makes this a prop­er std::binary_function:

	// HELL YEAH, LET'S MAKE THIS A FUNCTOR
	void operator()(Vector3D_T &amp;vector3D, const ComponentType &amp;x) const {
		(this-&gt;*operationPtr)(vector3D, x);
	}

	void add(Vector3D_T &amp;vector3D, const ComponentType &amp;x) const {
		vector3D.*componentPtr += x;
	}

	void sub(Vector3D_T &amp;vector3D, const ComponentType &amp;x) const {
		vector3D.*componentPtr -= x;
	}
};

Wait a min­ute. This almost the same thing as from the arti­cle, just all weird look­ing. Feel­ing duped? You should be. Tem­plat­ing will make you feel all emp­ty inside like that. But let’s see what we can do with this now:

int main() {
	std::vector&lt;Vector3D&lt;float&gt; &gt; vs(5, Vector3D&lt;float&gt; (0, 2, 3)); // create five &lt;0, 2, 3&gt;s
	std::copy(vs.begin(), vs.end(), std::ostream_iterator&lt;Vector3D&lt;float&gt; &gt;(std::cout, &quot; &quot;));
	std::cout &lt;&lt; std::endl; // print out the list

In case you haven’t noticed yet, that’s work­ing code for writ­ing stuff to a stream; you can actu­al­ly get an out­put iter­a­tor from a std::ostream and copy into it as with any oth­er iter­a­tor.

std::cout &lt;&lt; &quot;Negating vectors...&quot; &lt;&lt; std::endl;
	std::transform(vs.begin(), vs.end(), vs.begin(), std::negate&lt;Vector3D&lt;float&gt; &gt;());
	std::copy(vs.begin(), vs.end(), std::ostream_iterator&lt;Vector3D&lt;float&gt; &gt;(std::cout, &quot; &quot;));
	std::cout &lt;&lt; std::endl; // print out the list

WHOA MAN, THAT’S A FANCY NEGATE. std::negate cre­ates a class fit­ting the unary_­op­er­a­tor con­cept, which is a func­tor of ari­ty one. Specif­i­cal­ly, it uses the tem­plat­ed class’s operator- in the func­tor to return the neg­a­tive of what­ev­er is passed to the func­tor.

More fanci­ness:

	Operation&lt;Vector3D&lt;float&gt; &gt; vectorOp(&amp;Operation&lt;Vector3D&lt;float&gt; &gt;::add, &amp;Vector3D&lt;float&gt;::z);
	std::cout &lt;&lt; &quot;Adding to component z...&quot; &lt;&lt; std::endl;
	std::for_each(vs.begin(), vs.end(), std::bind2nd(vectorOp, 1.f));
	std::copy(vs.begin(), vs.end(), std::ostream_iterator&lt;Vector3D&lt;float&gt; &gt;(std::cout, &quot; &quot;));
	std::cout &lt;&lt; std::endl; // print out the list again

	vectorOp.setOperation(&amp;Operation&lt;Vector3D&lt;float&gt; &gt;::sub); // note the use of &amp; operator
	vectorOp.setComponent(&amp;Vector3D&lt;float&gt;::y);
	std::cout &lt;&lt; &quot;Subtracting from component y...&quot; &lt;&lt; std::endl;
	std::for_each(vs.begin(), vs.end(), std::bind2nd(vectorOp, 3.f));
	std::copy(vs.begin(), vs.end(), std::ostream_iterator&lt;Vector3D&lt;float&gt; &gt;(std::cout, &quot; &quot;));
	std::cout &lt;&lt; std::endl; // print out the list again

	return EXIT_SUCCESS;
}

Yes, there I am actu­al­ly “bind­ing” a fixed val­ue to the sec­ond para­me­ter of my func­tor, some­thing which required the use of std::binary_function to work. There is a bet­ter alter­na­tive that doesn’t require this, nor restrict us to bina­ry (ari­ty-two) func­tors, nor require us to spec­i­fy the para­me­ter to bind in such a cum­ber­some way. It’s called boost::bind, and you’re not going to use it because you’ll dis­cov­er that boost::lambda is bet­ter in every regard, and that you’ll be turned off by hav­ing to stick Boost’s bulk into code you found on a blog.

Next steps? Well, we should doc­u­ment the hell out of this. Mmm, yeah, let’s bring in some Doxy­gen, or even bet­ter, some light­weight bou­tique doc­u­men­ta­tion gen­er­a­tor! Let’s write some embed­ded doc­u­men­ta… eh, we’re too lazy.