Ken Y-N
Ken Y-N

Reputation: 15009

Make a constructor parameter into a template parameter

I have a home-brew ring buffer class like this:

template<typename T, int maxElements>
class RingBuffer
{
};

class Foo
{
    RingBuffer<int, 2000> ring;
};

This is a performance bottleneck, as a quick replacement with boost::circular_buffer showed a 7% saving in the overall code. However, I need to explicitly construct the boost::circular_buffer like this:

class Foo
{
    boost::circular_buffer<int> ring;
public:
    Foo() : ring(2000) {}
};

Is there a neat idiom (or indeed another Boost template!) that I can wrap boost::circular_buffer with to say something like:

class Foo
{
    auto_construct<boost::circular_buffer<int>, 2000> ring;
};

So I no longer need to touch the Foo::Foo()?

Update: Although in-class initialisers get close, I also have typedefs:

using Ring200 = RingBuffer<int, 2000>;

So I would like:

using BoostRing2000 = auto_construct<boost::circular_buffer<int>, 2000>;

So that I don't need to remember the {2000} every time I declare one.

Upvotes: 1

Views: 88

Answers (2)

lubgr
lubgr

Reputation: 38267

You can still use in-class initializers with a non-type template parameter for your Foo wrapper.

template <std::size_t N> struct Foo {
   boost::circular_buffer<int> ring{N};
};

And the appropriate type alias would be

using BoostRing2000 = Foo<2000>;

If it's desired to keep the actual type of the data stored flexible, you can add another template parameter such that

template <class T, std::size_t N> struct Foo {
   boost::circular_buffer<T> ring{N};
};

which allows for fine grained control over the type aliases, e.g.

using BoostIntRing2000 = Foo<int, 200>;
template <class T> using BoostRing2000 = Foo<T, 200>;

and the instantiations now read

BoostIntRing2000 someIntegerRing;
BoostRing2000<double> someDoubleRing;

Upvotes: 2

A default member initializer can do.

class Foo
{
    boost::circular_buffer<int> ring{2000};
};

Assuming your intent is to only touch the member definition. It also carries the advantage that if you ever change your mind for a specific constructor, it's not a hassle to modify. Just add a member initializer to that c'tor and your'e done.


Given the edit, I'm unfamiliar with anything in boost the can do what you are after. But another approach, that will also save you some substitution, is to implement your homebrewed RingBuffer as a thin wrapper around boost::circular_buffer.

template<typename T, int maxElements>
class RingBuffer : boost::circular_buffer<T> // Can also be a member instead of privately inherited
{
  // Now pull what we need with using delcarations and define a c'tor

   public:

   RingBuffer() : boost::circular_buffer<T>(maxElements) {}
};

Upvotes: 4

Related Questions