Viatorus
Viatorus

Reputation: 1903

Initialize nested template classes

I have many template classes, which work in a arbitrary order together (share the same concept).

Supposing that I have:

template<typename T>
class A {
  T t_;
public:
  void call() {
    // Do something.
    t_.call();
  }
};

template<typename T, typename U>
class B {
  T t_;
  U u_;
public:
  void call() {
    // Do something.
    t_.call();
    // Do something.
    u_.call();
  }
};

class C {
public:
  void call() {
    // Do something.
  }
};

And I have the following instantiated class:

using Foo = A<B<A<C>,C>>;

Lets assume, C need a special constructor (or initializer function) to work probably. Something I do only know at runtime.

struct C {
  void init(int);
  void call();
};

How can I initialize Foo probably? Or any other nested class combination?

My current workaround is to define C as:

template<typename I>
struct C {
  C() : var_(I::get())
  void call();
};

And create Foo inside a function:

int main()
{
  int i = 0;

  struct HelperC1 {
    static int get(bool set = false, int value = 0) {
      static int value_ = value;
      if (set) value_ = value;
      return value_;
    }
  } helperC1;

  struct HelperC2 {
    static int get(bool set = false, int value = 0) {
      static int value_ = value;
      if (set) value_ = value;
      return value_;
    }
  } helperC2;

  helperC1.get(true, i);
  helperC2.get(true, i+1);

  A<B<A<C<HelperC1>>,C<HelperC2>>> foo;   
  foo.call();

  return 0;
}

Live example.

You see, this workaround is not very handy. Another approach would be to call the first constructor of Foo with the arguments and redirect them to C but this is very bad for different class combinations like:

using Bar = A<B<A<C>,<B<B<A,C>,C>>>;

Question: How to initialize nested (template) classes with a runtime arguments (better/in a nicer, cleaner way)?

Upvotes: 2

Views: 514

Answers (2)

Christopher Oicles
Christopher Oicles

Reputation: 3107

This example builds values for branching template types with move construction and forwarding helper functions.

The forwarding helpers wrap constructors, using type inference to avoid the need to specify each constructor with its complicated parameters.

In this example, the call() function dumps the parameter structure and values of an object's children.

#include <iostream>
#include <utility>

template<typename T>
class A {
    T t;
public:
    A(T&& t) : t{std::move(t)} {}
    void call() {
        std::cout << "A<";
        t.call();
        std::cout << ">";
    }
};
template <typename T>
inline A<T> mkA(T&& t) { return A<T>{std::forward<T>(t)}; }

template<typename T, typename U>
class B {
    T t;
    U u;
public:
    B(T&& t, U&& u) : t{std::move(t)}, u{std::move(u)} {}

    void call() {
        std::cout << "B<";
        t.call();
        std::cout << ",";
        u.call();
        std::cout << ">";
    }
};
template <typename T, typename U>
inline B<T,U> mkB(T&& t, U&& u) { 
    return B<T,U>{std::forward<T>(t), std::forward<U>(u)};
}

class C {
    int c;
public:
    C(int c) : c{c} {}
    void call() {
        std::cout << "C(" << c << ")";
    }
};

int main() {
    auto bar = mkA(mkB(mkA(C{1}), mkB(mkB(mkA(C{2}),C{3}), C{4})));
    bar.call();
    std::cout << '\n';
}

This outputs:

A<B<A<C(1)>,B<B<A<C(2)>,C(3)>,C(4)>>>

Upvotes: 1

xvan
xvan

Reputation: 4855

You could use pointers and build foo with already constructed and initialized objects. ie:

UNTESTED CODE

template<typename T>
 class A {
  T* t_;

public:
  A(T* valptr) : t_(valptr){}
  ~A(){ delete t_ ; }

  void call() {
    // Do something.
    t_.call();
  }
};

template<typename T, typename U>
class B {
  T* t_;
  U* u_;

public:
  B(T* val1ptr, U* val2ptr):t_(val1ptr), u_(val2ptr){}
  ~B(){delete val1ptr; delete val2ptr;}

  void call() {
    // Do something.
    t_->call();
    // Do something.
    u_->call();
  }
};

class C {
  private:
    int x_;
  public:
  C(int x):x_(x){}
  void call() {
    // Do something.
  }
};

Usage:

A<B<A<C>,C>> foo( new B<A<C>,C>(new A<C>(new C(3) ), new C(3) ) );

Upvotes: 2

Related Questions