Better way to write an object generator for an RAII template class?
- by Dan
I would like to write an object generator for a templated RAII class -- basically a function template to construct an object using type deduction of parameters so the types don't have to be specified explicitly.
The problem I foresee is that the helper function that takes care of type deduction for me is going to return the object by value, which will result in a premature call to the RAII destructor when the copy is made. Perhaps C++0x move semantics could help but that's not an option for me.
Anyone seen this problem before and have a good solution?
This is what I have:
template<typename T, typename U, typename V>
class FooAdder
{
private:
typedef OtherThing<T, U, V> Thing;
Thing &thing_;
int a_;
// many other members
public:
FooAdder(Thing &thing, int a);
~FooAdder();
void foo(T t, U u);
void bar(V v);
};
The gist is that OtherThing has a horrible interface, and FooAdder is supposed to make it easier to use. The intended use is roughly like this:
FooAdder(myThing, 2)
.foo(3, 4)
.foo(5, 6)
.bar(7)
.foo(8, 9);
The FooAdder constructor initializes some internal data structures. The foo and bar methods populate those data structures. The ~FooAdder dtor wraps things up and calls a method on thing_, taking care of all the nastiness.
That would work fine if FooAdder wasn't a template. But since it is, I would need to put the types in, more like this:
FooAdder<Abc, Def, Ghi>(myThing, 2) ...
That's annoying, because the types can be inferred based on myThing. So I would prefer to create a templated object generator, similar to std::make_pair, that will do the type deduction for me. Something like this:
template<typename T, typename U, typename V>
FooAdder<T, U, V>
AddFoo(Thing &thing, int a)
{
return FooAdder<T, U, V>(thing, a);
}
That seems problematic: because it returns by value, the stack temporary object will be destructed, which will cause the RAII dtor to run prematurely.
One thought I had was to give FooAdder a copy ctor with move semantics, kinda like std::auto_ptr. But I would like to do this without dynamic memory allocation, so I thought the copy ctor could set a flag within FooAdder indicating the dtor shouldn't do the wrap-up. Like this:
FooAdder(FooAdder &rhs) // Note: rhs is not const
: thing_(rhs.thing_)
, a_(rhs.a_)
, // etc... lots of other members, annoying.
, moved(false)
{
rhs.moved = true;
}
~FooAdder()
{
if (!moved)
{
// do whatever it would have done
}
}
Seems clunky. Anyone got a better way?