
Brian McNamara <lorgon@cc.gatech.edu> writes:
On Fri, Feb 20, 2004 at 12:25:49PM -0500, David Abrahams wrote:
Brian McNamara <lorgon@cc.gatech.edu> writes:
On Thu, Feb 19, 2004 at 11:35:13PM -0500, David Abrahams wrote:
Brian McNamara <lorgon@cc.gatech.edu> writes:
(Despite the fact that no one wants to hear it, I would feel remiss if I didn't play Chicken Little and say "Fool's gold! Qualified calls and template specialization are the one true path to such customization!
You'd be wrong. It'd be nice if it were true, but qualified calls are subject to order dependencies, among other problems.
I'm not clear about this.
// lib.hpp namespace lib { template <class T> void f(T); template <class T> void g(T x) { lib::f(x); } }
// user.hpp #include "lib.hpp" namespace user { struct MyClass {}; } namespace lib { template <> void f( user::MyClass ) { /* print "foo" */ } Not an overload.
Yes, I know. Chicken Little says
Qualified calls and _template_specialization_ are the one true path to such customization! [emphasis added]
But he's wrong. As I've been trying to say, qualified calls in a function template are bound at the point of definition, so if a better overload comes later it isn't considered. That's why you should use parens.
}
// user.cpp #include "user.hpp" int main() { user::MyClass m; lib::g(m); }
Would that not print "foo"? What is the order dependency?
That's a specialization. Actually, there'd still be an order dependency if g wasn't a function template, but that's beside the point.
I'm not sure what your second sentence there is trying to tell me; can you give a short example?
Simple: specializations that follow the point of instantiation aren't considered. This program exits with an error: template <class T> int f(T) { return 1; } int main() { return ::f(0); } template <> int f(int) { return 0; }
(If g isn't a function template, what would it be?)
A regular function.
(I don't think I have access to a compiler that supposedly does this right, or else I'd try it myself.) What are the other problems? (I know one: function templates can't be "partially" specialized, which means you sometimes need to use a class helper, ugh.)
specialization interacts badly with overloading too:
template <class T> int f(T); template <> int f(int*); template <class T> void f(T*);
int x = 0; int y = f(&x); // error; can't convert void to int.
Indeed; recall that part of Chicken Little's thesis is
All designs based on overloading or ADL will end in tears!
There's no ADL here.
the relevant part here being "Overloading bad!" (in the context of library/user customization designs).
I understand this purist's POV, but then, "Specialization Bad", too, for similar but even worse reasons: template <class T> struct fu { int bar(); }; template <> struct fu<int> { typedef whiskey bar; }; -- Dave Abrahams Boost Consulting www.boost-consulting.com