|
Boost : |
From: David Abrahams (dave_at_[hidden])
Date: 2002-08-20 12:32:07
Hi All,
A question from one of my Boost.Python users (see
http://mail.python.org/pipermail/c++-sig/2002-August/001946.html
http://mail.python.org/pipermail/c++-sig/2002-August/001947.html)
prompted me to think seriously about this problem:
"How can we write generic code which constructs new objects?"
[I've cc'd Andy Koenig here because he's responsible for
value-initialization, which comes into this conversation. I've cc'd Herb
because, well, maybe he's already written a GOTW on this one]
I have to admit, I don't know the rules, but they seem terribly nonuniform
to me. The specific problem I'm trying to solve is the implementation of
boost/python/implicitly_convertible.hpp:
template <class Source, class Target>
void implicitly_convertible();
Requires: The expression Target(s), where s is of type Source, is
valid.
Internally, this function needs to do a placement-new of the target type.
Naturally, I thought that internally writing:
new (storage) Target(src)
would work. However, that doesn't work for all types. For example, if src
is an int and Target is an enum type, I can write:
Target x = Target(src);
but not:
Target* p = new Target(src);
That's just wierd. The only solution I know is:
Target* p = new Target(Target(src));
but then that requires copy-constructibility of Target. So I think
ultimately, I need to do some kind of compile-time dispatching to determine
the type category of Target, only using this copy-construction workaround .
Do we even have a single type trait that covers it? I don't think so,
unless is_scalar<> includes is_enum<> (that's not evident from our docs).
A related issue comes up when you want to convert from one type to another,
but only if the source type can be implicitly converted to the target.
Writing:
Target(src)
works unless Target is a builtin, in which case this seems to act just like
a dangerous C-style cast. This makes me nervous about using explicit
construction in any generic code.
enum Foo { foo = 42 };
template <class T> void f(T const&);
template <class Src, Target> int g(Src const& x)
{
f(Target(x));
return 0;
}
int x = g<Foo>(4.4); // OK
I guess I could use a named variable instead:
template <class Src, Target> int g(Src const& x)
{
Target t = x;
f(t);
return 0;
}
Is that the best answer?
Finally, there's the issue of default construction. If I want to
generically declare a default-constructed object of type T, I can't write:
T x;
since builtins (and I presume, enums) won't be initialized. I can't write:
T x();
since that just declares a function. What can/should I write?
And finally, the $60,000 question: is there a library solution for these
problems?
-Dave
-----------------------------------------------------------
David Abrahams * Boost Consulting
dave_at_[hidden] * http://www.boost-consulting.com
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk