简体   繁体   English

条件类模板构造函数

[英]Conditional class template constructor

I am trying to make a class that has conditional members as below (sample code to illustrate problem): 我试图使一个具有条件成员的类如下(示例代码来说明问题):

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

I need to have two conditional constructors depending on the bool b but this does not compile. 我需要根据bool b有两个条件构造函数,但这不能编译。 I tried specializing the constructors with bool value: 我试着用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) {};

but that doesn't compile either because partial function template specializations are not allowed. 但这不能编译,因为不允许部分函数模板专门化。

Is there a way to achieve this? 有没有办法做到这一点?

The problem with 问题所在

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

is that a constructor's mem-initializer-list can name only virtual base classes, direct base classes, and direct non-static data members, but never an inherited member like m . 是构造函数的mem-initializer-list只能命名虚拟基类,直接基类和直接非静态数据成员,而不能命名像m这样的继承成员。 This is because the member of a base class is initialized by the base class subobject constructor, so it can't be initialized again (though it could be assigned). 这是因为基类的成员是由基类子对象构造函数初始化的,因此无法再次初始化(尽管可以对其进行分配)。

You can instead specify the base class initializer. 您可以改为指定基类初始化程序。 With this example, conditional_members is an aggregate, so aggregate initialization will work: 在此示例中, conditional_members是一个聚合,因此聚合初始化将起作用:

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

Though with just that, you might get some strange side effects from the fact that my_class specializations always have the two constructors declared, even if it might be invalid to actually instantiate one constructor or the other. 尽管这样,您可能会因my_class专业化始终声明了两个构造函数而产生一些奇怪的副作用,即使实际上实例化一个构造函数或另一个构造函数可能无效。

Here's an SFINAE trick to make the constructors conditionally effectively invisible, depending on b : 这是一个SFINAE技巧,使构造函数有条件地有效地不可见,具体取决于b

#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) {}
};

As a preview, with C++20 constraints, you'll be able to write it this nice, simpler way instead: 作为预览,在具有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) {}
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM