This is a little page where I will try to capture (hopefully) interesting c++ code snippets, thoughts, tips, tricks and woes. I don't suck this stuff out of my thumb; there are no ads on this page and I am not looking for a job. Instead they are little pieces of real code that I find beautiful or ugly enough to spend my time writing about. The most recent entries are on top. You may also be interested in my C++ Startup blog.
If you ever had to write
return auto_ptr<foo> (0);
you must have wondered if there is a way to just write
return 0;
Apparently there is. The idea is to overload auto_ptr
's
c-tor in such a way that it would only allow zero-initialization. Here
is the code:
template <typename X> struct auto_ptr { typedef void (auto_ptr::*impossible_member_function_type) (...); auto_ptr (impossible_member_function_type) : x_ (0) { } explicit auto_ptr (X* x = 0) : x_ (x) { } private: X* x_; };
The trick is to have c-tor's argument to be of a pointer to member
function type. And not just any pointer to member function type but the
one for which there couldn't possibly be a matching member function. As
a result, the only valid argument for this c-tor is 0
.
There is one problem with this code but, as it usually happens, I only
uncovered it after I've published the first version. The problem
becomes apparent when we try to use the old way of zero-initializing
auto_ptr
:
return auto_ptr<foo> (0);
Such a call to auto_ptr
's c-tor is ambiguous because both
c-tors presented above are equally applicable (both require one implicit
conversion of their arguments). So how can we inhibit such implicit
conversion for one of the c-tors? That's right, nothing inhibits any
type of conversion as well as automatic template argument deduction:
template <typename X> struct auto_ptr { typedef void (auto_ptr::*impossible_member_function_type) (...); auto_ptr (impossible_member_function_type) : x_ (0) { } template <typename Y> explicit auto_ptr (Y* x = 0) : x_ (x) { } private: X* x_; };
Last updated on 03 Oct 2005
Consider this code:
struct title { title (std::string const&); }; void f () { title t ("hello"); }
Looks innocent, right? Indeed, this code appear to be legal c++. How about this:
struct title { title (std::string const&); }; struct book { book (title const&); }; void f () { book b ("hello"); }
Looks equally innocent to me. However, this is illegal. I can't think off my head what would break should such conversion chains be allowed. Also I am lazy to go search through the standard for the relevant verse; if you find it let me know and I will mention it here.
Last updated on 29 Aug 2005
Here is the problem: I needed about 40 operator<<
implementations for 40 different types (that happened in the
XML Schema to C++
Compiler runtime library, if you must know). All implementations are
pretty much the same. Is there anything better than just copy-n-pasting
40 times?
Note that I can't simply write something like this:
template <typename x> void operator<< (element&, x const&) { // ... }
Why? Because that would apply to all the types, not just my 40 or so. What I would really like is to somehow restrict this implementation to my types. Would be nice if we could make this operator template apply only to a certain namespace, e.g. (not a real c++),
namespace n { // My types are here. } template <typename x> void operator<< (element&, n::x const&) { // ... }
Apparently we can do something close to this using argument-dependant lookup (ADL) and namespaces:
struct element {}; namespace n { struct a {}; template <typename x> void operator<< (element&, x const&) { // ... } } struct b {}; void f () { element e; n::a a; b b; e << a; // ok e << b; // error }
Of course this will blow if somebody says using namespace n;
Last updated on 10 Aug 2005
Copyright © 2005 Boris Kolpackov.
Last updated on 28 July 2005