0

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.

  • If T == T1 a compiler does NOT call the template constuctor but rather copy constructor. One should keep in mind that apparently the constructor below alone is not enough to solve the general purpose case. That was noted in the comment here
template <typename T>
Type1(T t) : init_{std::is_same<Type1, T>::value} {}
  • References have to be used in the static casts below as per comment here
static_cast<Type1>(types).Print();
static_cast<Type2>(types).Print();
  • Compiler allows the syntax below but there is no way to provide an explicit template argument. Hence the commented code does not work. That was explained in the comment here. A topic about this problem at stackoverlow can be read here.
template <typename T>
Type1() : init_{std::is_same<Type1, T>::value} {};
TruLa
  • 1,031
  • 11
  • 21
  • Off the top: `template Type1()` can never be used, as there's no syntax to provide explicit template arguments when invoking a constructor, and there's no parameter to deduce them from either. – Igor Tandetnik Apr 19 '21 at 15:16
  • 1
    `static_cast(types)` creates a temporary of type `Type1`, using templated constructor with `types` as its argument. It's equivalent to `Type1{types}`. Naturally, the type of `types` is not `Type1`. You are calling `Print()` on that temporary, not on `Type1` subobject within `types` – Igor Tandetnik Apr 19 '21 at 15:24
  • @IgorTandetnik Many thanks for helping me to sort this out. I updated the original post with all the problems that the original code has. – TruLa Apr 20 '21 at 08:55

1 Answers1

1

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).

mattlangford
  • 1,260
  • 1
  • 8
  • 12
  • I think together with the previous comments that fully resolves the problem. I updated my original post and mark your answer as accepted. Many thanks for your time! – TruLa Apr 20 '21 at 08:57