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.

Restricting to zero-initialization

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

Implicit conversion chains.

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

Restricting applicability of functions with ADL and namespaces.

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.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, version 1.2; with no Invariant Sections, no Front-Cover Texts and no Back-Cover Texts.

Last updated on 28 July 2005