Sometimes we like to take a large parameter by reference, and also to make the reference const if possible to advertize that it is an input parameter. But by making the reference const, the compiler then allows itself to convert data if it’s of the wrong type. This means it’s not as efficient, but more worrying is the fact that I think I am referring to the original data; perhaps I will take it’s address, not realizing that I am, in effect, taking the address of a temporary.
The call to bar in this code fails. This is desirable, because the reference is not of the correct type. The call to bar_const is also of the wrong type, but it silently compiles. This is undesirable for me.
#include<vector>
using namespace std;
int vi;
void foo(int &) { }
void bar(long &) { }
void bar_const(const long &) { }
int main() {
foo(vi);
// bar(vi); // compiler error, as expected/desired
bar_const(vi);
}
What’s the safest way to pass a lightweight, read-only reference? I’m tempted to create a new reference-like template.
(Obviously, int and long are very small types. But I have been caught out with larger structures which can be converted to each other. I don’t want this to silently happen when I’m taking a const reference. Sometimes, marking the constructors as explicit helps, but that is not ideal)
Update: I imagine a system like the following: Imagine having two functions X byVal(); and X& byRef(); and the following block of code:
X x;
const_lvalue_ref<X> a = x; // I want this to compile
const_lvalue_ref<X> b = byVal(); // I want this to fail at compile time
const_lvalue_ref<X> c = byRef(); // I want this to compile
That example is based on local variables, but I want it to also work with parameters. I want to get some sort of error message if I’m accidentally passing a ref-to-temporary or a ref-to-a-copy when I think I’ll passing something lightweight such as a ref-to-lvalue. This is just a ‘coding standard’ thing – if I actually want to allow passing a ref to a temporary, then I’ll use a straightforward const X&. (I’m finding this piece on Boost’s FOREACH to be quite useful.)
(Answering my own question thanks to this great answer on another question I asked. Thanks @hvd.)
In short, marking a function parameter as
volatilemeans that it cannot be bound to an rvalue. (Can anybody nail down a standard quote for that? Temporaries can be bound toconst&, but not toconst volatile &apparently. This is what I get on g++-4.6.1. (Extra: see this extended comment stream for some gory details that are way over my head 🙂 ))But, you don’t actually want the parameters to be
volatile. So I’ve written a small wrapper to const_cast thevolatileaway. So the signature of foo becomes this instead:where the wrapper is:
This can be created from an lvalue only
Any downsides? It might mean that I accidentally misuse an object that is truly volatile, but then again I’ve never used
volatilebefore in my life. So this is the right solution for me, I think.I hope to get in the habit of doing this with all suitable parameters by default.
Demo on ideone