【问题标题】:Call template constructors of an inherited parameter pack调用继承参数包的模板构造函数
【发布时间】:2021-07-13 13:28:32
【问题描述】:

下面的代码有两个可能相关的问题。

它只是分别定义了Type1Type2 两种类型,以及继承自这两种类型的“聚合”类型Types

我的最终目标是让注释的构造函数工作以避免临时变量初始化。如果我取消注释Types 下的代码,编译器会给我一个错误:

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

我试图克服这个问题并想出了可以编译的代码。但是它没有给出预期的输出。

预期的输出是

Type1:1
Type2:0

实际输出为

Type1:0
Type2:0

我不知道我的两个问题是否相互关联。 我想它们都是由于我可能缺乏对参数包和继承的理解而引起的,因此我将它们都发布了。

如果有人能阐明这两个问题,我将不胜感激。

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();
}

更新

感谢Igor Tandetnikmattlangford,我认为这个问题可以解决

正如现实生活中发生的那样,如果您认为自己不了解某件事,您经常会错过不止一个。

  • 如果T == T1 编译器不调用模板构造函数,而是调用复制构造函数。应该记住,仅下面的构造函数显然不足以解决通用情况。评论中提到了here
template <typename T>
Type1(T t) : init_{std::is_same<Type1, T>::value} {}
  • 根据评论here,必须在下面的静态转换中使用引用
static_cast<Type1>(types).Print();
static_cast<Type2>(types).Print();
  • 编译器允许使用以下语法,但无法提供显式模板参数。因此,注释代码不起作用。 这在评论here 中有解释。可以阅读 stackoverlow 上有关此问题的主题 here
template <typename T>
Type1() : init_{std::is_same<Type1, T>::value} {};

【问题讨论】:

  • 关闭顶部:template &lt;typename T&gt; Type1() 永远不能使用,因为在调用构造函数时没有提供显式模板参数的语法,也没有参数可以从中推断出它们。
  • static_cast&lt;Type1&gt;(types) 创建一个类型为 Type1 的临时对象,使用带有 types 作为其参数的模板化构造函数。它相当于Type1{types}。当然types 的类型不是Type1。您在该临时对象上调用 Print(),而不是在 types 内的 Type1 子对象上调用
  • @IgorTandetnik 非常感谢您帮助我解决这个问题。我用原始代码存在的所有问题更新了原始帖子。

标签: c++ templates inheritance constructor c++17


【解决方案1】:

这似乎是自动生成和使用复制构造函数而不是模板化函数。我明确添加了复制构造函数:

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

对这两种似乎都有效的类型。

另一个注意事项是将打印行切换为:

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

因为如果你只是 static_cast 到非引用类型,就会产生副本(如果它甚至是定义的行为)。

【讨论】:

  • 我认为与之前的cmets一起完全解决了这个问题。我更新了我的原始帖子并将您的答案标记为已接受。非常感谢您的宝贵时间!
猜你喜欢
  • 2019-12-14
  • 2019-12-14
  • 1970-01-01
  • 2012-09-11
  • 1970-01-01
  • 2013-05-21
  • 1970-01-01
  • 1970-01-01
  • 2016-03-04
相关资源
最近更新 更多