TruLa
TruLa

Reputation: 1147

Call template constructors of an inherited parameter pack

I'm having two probably related problems with the code below.

It just defines two types Type1 and Type2 respectively and an "aggregate" type Types that inherits from both of them.

My final goal is to make the commented constructor work to avoid having a temporary variable initialization. If I un-comment the code under Types the compiler gives me an error:

error: class ‘Types<Args>’ does not have any field named ‘Args’

I tried to overcome the problem and came up with the code that compiles. However it does not give the expected output.

The expected output is

Type1:1
Type2:0

The actual output is

Type1:0
Type2:0

I do not know if two of my problems relate to each other. I guess that both of them arise from my possible lack of understanding parameter pack and inheritance hence I am posting both of them.

I appreciate if someone could shed some light on both of the problems.

struct Type1 {
  Type1() = default;
  template <typename T>
  Type1() : init_{std::is_same<Type1, T>::value} {};
  template <typename T>
  Type1(T t) : init_{std::is_same<Type1, T>::value} {}

  void Print() const { std::cout << "Type1:" << init_ << std::endl; }
  bool init_{false};
};

struct Type2 {
  Type2() = default;
  template <typename T>
  Type2() : init_{std::is_same<Type2, T>::value} {};
  template <typename T>
  Type2(T) : init_{std::is_same<Type2, T>::value} {}

  void Print() const { std::cout << "Type2:" << init_ << std::endl; }
  bool init_{false};
};

template <typename... Args>
class Types : public Args... {
 public:
  // error: class ‘Types<Args>’ does not have any field named ‘Args’
  //
  //template <typename T>
  //Types()
  //  : Args<T>()... {}

  template <typename T>
  Types(T t)
    : Args(t)... {}
};

int main() {
  Types<Type1, Type2> types(Type1{});

  static_cast<Type1>(types).Print();
  static_cast<Type2>(types).Print();
}

UPDATE:

I consider the question to be solved thanks to Igor Tandetnik and mattlangford

As it happens in real life, if you think that you do not understand a thing you often miss more than one.

template <typename T>
Type1(T t) : init_{std::is_same<Type1, T>::value} {}
static_cast<Type1>(types).Print();
static_cast<Type2>(types).Print();
template <typename T>
Type1() : init_{std::is_same<Type1, T>::value} {};

Upvotes: 0

Views: 55

Answers (1)

mattlangford
mattlangford

Reputation: 1260

It seems like it's something with the copy constructor being automatically generated and used instead of the templated function. I added the copy constructor explicitly:

  template <typename T>
  Type1(T t) {}
  Type1(const Type1& t) : init_{true} {}

to both types that seemed to work.

Another note would be to switch the print lines to:

  static_cast<Type1&>(types).Print();
  static_cast<Type2&>(types).Print();

since if you just static_cast to the non-reference types there will be copies being made (if it's even defined behavior).

Upvotes: 1

Related Questions