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