Is there a template that can generate static / dynamically linked versions of a class?

I am working on some library code and I want users to be able to use static bindings if they are able. If they can't instantiate a class at compile time, I want a dynamic version of the class in there so that it can be instantiated at runtime.

For a quick example, let's say I have a struct template A:

template<bool dynamic, int value=0> struct A
{
    static const int Value = value;
};


template<> struct A<true>
{
    int Value;
    A(int value) : Value(value) {}
};

      

These definitions allow library users to instantiate A statically and dynamically:

A<true> dynamicA = A<true>(5);

A<false, 5> staticA;

      

The problem with this method is that I have to write the class definition twice. I can think of several ways to implement a template that will generate both versions on its own, but I can see that it becomes a lot of work. Especially for classes that will use a different number of parameters, for example:

// It would be much harder to generate a static version of this class, 
// though it is possible with type lists.  Also, the way I'm imagining it, 
// the resulting classes probably wouldn't be very easy to use.
struct A
{
   vector<int> Values;
    A(vector<int> value) : Values(value) {}
};

      

Is there a name for this pattern / problem? Is there a metaprogram library that has templates that can generate both definitions for me? How can I avoid having to write my class definitions twice?

+3


source to share


1 answer


There is a simple mechanism to get the parts that are not affected by the dynamic / static value problem in one place: put them in another class, call it basic_A

and call the static / dynamic value container you are showing in the question value_A

. There are various ways to connect value_A

and basic_A

to form a complete class A

:

  • Aggregation basic_A

    inside value_A

    . This would mean that you have to channel each method basic_A

    through value_A

    and provide the appropriate one-liners in both specializations value_A

    . It probably isn't that much because you need to duplicate all the one-liners, so scratch that.

  • Aggregation value_A

    inside basic_A

    . You will also need to make a basic_A

    template just to pass parameters value_A

    and provide the correct constructors for both specializations, perhaps by disabling them somehow and enabling them via SFINAE. Not very nice and convenient code. An alternative would be to make a common base class (interface) for the two specializations value_A

    , have an unique_ptr

    interface for that in, basic_A

    and pass a ready constructed constructor value_A

    in basic_A

    , at the cost of a virtual function call and indirect indirection when you want to access a value. Yuck, especially if it is A

    intended for the small and fast light class.

  • Inherit basic_A

    from value_A

    . The same issues as in 2. apply regarding constructors and template parameter passing.

  • Inherit value_A

    from basic_A

    . The design problem goes away, but now basic_A

    can't easily access the value value_A

    . One solution would be to have a pure virtual function getValue()

    in basic_A

    that two specializations must perform value_A

    . This again comes with the overhead of sending a virtual function, which may not be desirable for a small lightweight class, but allows encapsulation as it basic_A

    is non-template and can hide its implementation in the .cpp file. Another approach would be to use compiletime polymorphism in CRTP, which would do the basic_A

    template again.

Here are two examples for two approaches to 4:

4a: getValue()

as a virtual function:

//basic_a.hpp

struct basic_A {
  int foo() const;
  virtual int getValue() const = 0;
};

//basic_A.cpp
int basic_A::foo() const { return 10 * getValue(); }

      



4b: getValue()

vĂ­a CRTP

template <class Value_t>
struct basic_A {
  int foo() const { return 10 * value_(); }
private:
  int value_() const { return static_cast<Value_t const&>(*this).getValue(); }
};

      

The template A

aka. A_value

for 4b. For 4a it's pretty much the same, just lose the template arguments and parentheses from basic_A

, as it's a simple class:

template <bool dyn, int value = 0> 
struct A;

template <>
struct A<true, 0> : basic_A<A<true, 0>>
{
  int val;
  int getValue() const { return val; }
};

template <int value>
struct A<false, value> : basic_A<A<false,value>>
{
  int geValue() { return value; }
};

      

+3


source







All Articles