Re: template matching
assaf wrote:
What should bar() output and why?
class Base {};
class Derived : public Base {};
template <typename T> void foo(const T&) { cout << "a"; }
template <> void foo(const Base&) { cout << "b"; }
void bar()
{
foo(Derived());
}
"a" is always printed. I want a specialization of foo that would
handle all descendants of Base, while all other types are handled by
the primary template function. Is that possible?
No, or at least not without some meta-programming (and some
additional indirection).
The basic reason is simple: when performing overload resolution,
the compiler starts by building a set of callable functions.
For a template function, it tries to deduce the type, and if
that succeeds, it adds the specialization to the list of
callable functions. At this point, whether there is an explicit
specialization or not is irrelevant. In your case, of course,
the deduced specialization is foo<Derived>, which gets added to
the overload set. Once the overload set has been built, the
compiler chooses which function to call from it. Then, and only
then, if the chosen function is a template, the compiler
instantiates it. And it is only on instantiation that an
explicit specialization is taken into account: once (if) the
compiler has chosen to instantiate the specialization, an
explicit specialization will be used for that instantiation (if
one exists).
The problem you have is that no matter what you do, the compiler
will deduce foo<Derived>, and add it to the overload set. After
which, of course, the deduced foo<Derived> will be an exact
match, and thus be chosen over any other overload. The only
workaround I know of is to use helper functions, overloaded on
an additional parameter. Something like:
template< typename T >
void foo2( T const& ... ) { std::cout << "a" ; }
template< typename T >
void foo2( T const&, Base const& ) { std::cout << "b" ; }
template< typename T >
void foo( T const& obj ) { foo2( obj, obj ) ; }
In this case, when instantiating foo, the compiler will generate
implicit specializations for both instances of foo2, and add
them both to the overload set. And of course, the reference
initialization beats ... every time. Every time it can be
legally used, of course---call foo(SomeUnrelatedClass()), and
type deduction will fail for the second foo2, it won't get added
to the overload set, and with no other competition, the first
version gets called.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient?e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S?mard, 78210 St.-Cyr-l'?cole, France, +33 (0)1 30 23 00 34
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]