Search code examples
c++templatesmetaprogrammingalloca

alloca() of a templated array of types: how to do this?


I have a smart pointer type, and would like to construct an object that takes a pointer of that type and a count (dynamically calculated at runtime) and allocates enough memory from the stack to hold that many instances of the object the smart pointer points to. I can't seem to find quite the right syntax to achieve this; is it possible?

Given something like this

template<typename T>
class PointerWrapper
{
public:
    PointerWrapper( T const * _pointer ): m_pointer(_pointer) {}
    typedef T Type;
    T const * m_pointer;
};

template<typename T>
class SomeObject: public NoCopyOrAssign
{
public:
    SomeObject( void * _allocaBuffer, PointerWrapper<T> _source, int _count );
};

I want to do something like this:

void Test( PointerWrapper<int> _array, int _count )
{
    SomeObject<int> object = MakeSomeObject( _array, _count );
    // do some work with object
};

Code invoking the following macro doesn't compile, because the compiler cannot deduce SomeObject's template parameter from _wrappedPtr so complains that the template parameter is missing:

#define MakeSomeObject(_wrappedPtr, _runtimeCount) \
    SomeObject(alloca(sizeof(_wrappedPtr::Type)*_runtimeCount), \
                    _wrappedPtr, _runtimeCount)

If a function templated on the pointer wrapper type is used, although the compiler can deduce the types implicitly, code invoking it doesn't compile because SomeObject deliberately defines but does not implement a copy constructor or assignment operator; even if it did compile it would not do the right thing because the memory provided by alloca() would immediately go out of scope:

template<typename WrappedT>
SomeObject<typename WrappedT::Type> MakeSomeObject
    ( WrappedT _pointer, uint _runtimeCount )
{
    return SomeObject<typename WrappedT::Type>
        ( alloca(sizeof(typename WrappedT::Type)*_runtimeCount),
         _pointer, _runtimeCount );
}

I'd like to avoid passing the type into the macro as an argument since in the real code this would result in quite lengthy, hard-to-read statements at the point of use, however I guess that is a fallback if nothing better is possible.


Solution

  • Never mind, worked it out; the trick was to combine both approaches:

    template<typename WrappedT>
    SomeObject<typename WrappedT::Type> _MakeSomeObject
        ( void *_buffer, WrappedT _pointer, int _runtimeCount )
    {
        return SomeObject<typename WrappedT::Type>
            ( _buffer, _pointer, _runtimeCount );
    }
    
    template<typename WrappedT>
    int SizeT( WrappedT const _dummy ) { return sizeof(typename WrappedT::Type); }
    
    #define MakeSomeObject(_wrappedPtr, _runtimeCount) \
            _MakeSomeObject( alloca(SizeT(_wrappedPtr)*_runtimeCount), \
                 _wrappedPtr, _runtimeCount )