Tell me again about the safety of the language and how it keeps you from screwing yourself.
I must say, I'm a bit confused by this, as what you've done by typing the parametters as const T& is using the C++ mechanism for enjoining the compiler from doing a type promotion on a parameter, then complaining that it won't do type promotions.
Funny, I thought I was employing the C++ mechanism for reducing stack growth.
But wait, you'll complain, what if T is a BigAssClass type? Passing a BigAssType object by value is not recommended, as its too big, and you don't want to load the stack with such a monstrosity. That's quite true, but then, you wouldn't want to convert a BigAssObject to an int (or float, or double, or whatever), either, would you?
Really? I can imagine all kinds of scenarios of BigAssOrderedType. Here's a good one - suppose I have 2DVector and 3DVector. It makes sense that I can promote a 2Dvector to a 3Dvector - and if I mixed them, I'd certainly like promotion to happen towards 3Dvector. So maybe I implement operator 3Dvector on 2Dvector (being careful not to implement operator 2Dvector on 3Dvector lest we end up in ambiguity hell).
Boy, we've sure thought a lot about types without giving what the heck we're supposed to be doing a lick of thought. Thats why I think C++ is unredeemable shit. Working the type system consumes all available cycles and often - you still don't have an ironclad solution (like here).
The bottom line in this scenario is clearly, passing classes by value is just not worth the trouble it causes and the feature ought not to be there at all. Yes C allows you to pass structs by value - no that wasn't a good idea.
The smart thing to do would be to simply ignore the feature like Objective C did (objects only live on the heap - object references can live on the stack). The attempt to unify classes and structs was, in retrospect, a really bad choice.