Reputation: 35525
Occasionaly I find that I need a generic "pass through"-interface. For example for mix-in classes that forward their constructor arguments to the parent. Or for factory methods that forward their arguments to new
:
template<typename C>
C * Create();
template<typename C, typename Arg0>
C * Create(Arg0 & a);
template<typename C, typename Arg0, typename Arg1>
C * Create(Arg0 & a, Arg1 & arg1);
template<typename C, typename Arg0, typename Arg1, typename Arg2>
C * Create(Arg0 & a, Arg1 & arg1, Arg2 & arg2);
When putting the idea into practice I find that it usually works.
However, there are a few problems:
When passing the template arguments by value then sometimes reference-types drop their reference-ness along the way.
My attempted fix was so pass all arguments as non-const reference. This works for most of the cases because constness is preserved in the type itself and arguments that are passed by value are allowed to be converted to reference.
However, a notable exception is temporary const references. See my edit below for more info.
All this however is only my personal experience. I haven't seen this approach much in other codebases. Because of this I am interested to learn your ideas and insights on above issues.
My main questions are:
What are the general guidelines and best practices when designing this kind of interface?
How can I avoid losing type information? (Can it be avoided at all?)
Can you recommend any good examples of such a design?
In response to @Ben Voigt's comment. It seems he on to something. It works with a const char *
string that is bound to an lvalue, but it doesn't work when passing the result of typeinfo's name() method:
template<typename Arg0>
void Create(Arg0 & a) {}
void foo()
{
// works fine
const char * typeName = typeid(int).name();
Create(typeName);
// error: invalid initialization of non-const reference of type
// ‘const char*&’ from a temporary of type ‘const char*’
Create(typeid(int).name());
}
Upvotes: 1
Views: 187
Reputation: 145419
It's no big deal, really. You pass by reference to const
, and where a reference to non-const
is to be passed you require the caller to write ref(x)
. And instead of definining umpteen versions you define a supporting ArgPack
template once and for all.
Or, use C++0x purrfect führwarding.
Cheers & hth.,
Upvotes: 1
Reputation: 147018
Not in C++03, buddy. You must explicitly overload for every combination of const reference and non-const reference, which is exponential. In C++0x perfect forwarding and variadic templates will solve this problem.
Upvotes: 4