【问题标题】:Conditional class template constructor条件类模板构造函数
【发布时间】:2019-07-30 20:40:17
【问题描述】:

我正在尝试创建一个具有如下条件成员的类(示例代码来说明问题):

template<bool b>
struct conditional_members {};

template<>
struct conditional_members<true> 
{ int m; };

template<typename T, bool b>
struct my_class : public conditional_members<b>
{
    T n;

    // constructor for case when b is false
    my_class(T n) : n(n) {};

    // constructor for case when b is true
    my_class(T n, int m) : n(n), m(m) {};
};

我需要有两个取决于bool b 的条件构造函数,但这不会编译。我尝试使用 bool 值专门构造构造函数:

template<typename T>
my_class<T, true>::my_class(T n, int m) : n(n), m(m) {};

template<typename T>
my_class<T, false>::my_class(T n) : n(n) {};

但这也不能编译,因为不允许部分函数模板特化。

有没有办法做到这一点?

【问题讨论】:

  • m 不是成员,而是初始化基类。
  • 你想通过这样的结构解决什么问题?
  • @Igor 当b 为真时,我相信m 是继承成员
  • @NathanOliver 这是一小段代码来说明问题。 my_class 会有其他成员函数,在某些情况下可能需要 conditional_members,但并非总是如此。 conditional_members 的成员可能很大,所以我不想总是拥有它们,即使它们不使用。

标签: c++ templates template-meta-programming


【解决方案1】:

问题

// constructor for case when b is true
my_class(T n, int m) : n(n), m(m) {};

是构造函数的 mem-initializer-list 只能命名虚拟基类、直接基类和直接非静态数据成员,但不能命名像 m 这样的继承成员。这是因为基类的成员是由基类的子对象构造函数初始化的,所以不能再次初始化(虽然可以赋值)。

您可以改为指定基类初始化程序。在此示例中,conditional_members 是一个聚合,因此聚合初始化将起作用:

// constructor for case when b is true
my_class(T n, int m) : n(n), conditional_members<b>{m} {};

尽管如此,您可能会因为my_class 特化总是声明两个构造函数这一事实而得到一些奇怪的副作用,即使实际实例化一个或另一个构造函数可能是无效的。

根据b,这是使构造函数有条件地有效不可见的 SFINAE 技巧:

#include <type_traits>

// Define conditional_members as before.

template<typename T, bool b>
class my_class : public conditional_members<b>
{
    T n;

public:
    // constructor for case when b is false
    template <typename = std::enable_if_t<!b>>
    my_class(T n) : n(n) {}

    // constructor for case when b is true
    template <typename = std::enable_if_t<b>>
    my_class(T n, int m) : conditional_members<b>{m}, n(n) {}
};

作为预览,在 C++20 约束下,您将能够以这种更好、更简单的方式编写它:

template<typename T, bool b>
class my_class : public conditional_members<b>
{
    T n;

public:
    // constructor for case when b is false
    my_class(T n) requires(!b) : n(n) {}

    // constructor for case when b is true
    my_class(T n, int m) requires(b) : conditional_members<b>{m}, n(n) {}
};

【讨论】:

  • 谢谢!我曾尝试过enable_if,但我仍在使用成员初始化器列表,而不是使用this 在构造函数主体中初始化m
  • 另外,enable_if_t 在这里不起作用,因为b 是一个布尔值,而不是true_typefalse_type。只是使用enable_if 工作正常。
  • @Bilentor 不需要在ctor体中赋值m,只需初始化基类:: conditional_members&lt;b&gt;(m)
  • @Bilentor 错了,std::enable_ifstd::enable_if_t 模板都接受 bool 作为它们的第一个参数。
  • @IgorR。好的,除了聚合初始化之外,您需要花括号,而不是括号。 : conditional_members&lt;b&gt;{m}
猜你喜欢
  • 2021-07-24
  • 2020-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-08
  • 2013-05-30
  • 2016-03-22
  • 2015-07-03
相关资源
最近更新 更多