My actual usecase takes a few more arguments but it simplifies to this:
template< typename Arg1 >
bool algorithm( Arg1&& p1, **p2 here** );
With just that its evident that Arg1 will collapse in some way and likely become some kind of reference. p1 is also an output of the algorithm and so if the caller chooses to pass in an lvalue, the function will return with the original parameter modified to reflect where it left off.
However p2 is of the same type but will never be modified. So actually I'd like to put a 'const' promise in there for correctness. Clearly if Arg1 deduces to be a reference, I cannot add const to it.
So my solution is this:
template< class T >
struct make_const_ref
{
typedef typename std::add_reference< typename std::add_const< typename std::remove_reference< T >::type >::type >::type type;
};
template< typename Arg1 >
bool algorithm( Arg1&& p1, typename make_const_ref<Arg1>::type p2 );
Which goes through a bunch of silly machinations to remove some qualifiers and then stick the const& back on.
So my questions are:
1) Is this the best way of doing it?
2) Is there a context under which this will fail? Right now it seems pretty good to me.
I can think of one change that is surprising, but does not result in outright failure. The second parameter is disabled from argument deduction, so the type no longer has to match the first parameter type exactly. This allows for implicit conversions to be accepted, as-if the template argument were specified for the function. An example:
whereas the expression:
will fail to compile with
algorithm(0, Foo{0})
unless it was explicitlyalgorithm<int>(0, Foo{0})
. If you were hoping for exact matches only, then this could be problematic. In some cases this desirable; boost::clamp is one example I am aware of that does this intentionally.Bonus
This is similar to some of the comments to your question, but the trait can be simplified:
std::add_lvalue_reference will do what you want in all situations.
Edit
I put this as comment but it should probably go here. This is probably easier:
All you are trying to do is disable argument deduction for the second parameter, and take it by const-reference. This is doing just that.