如何根据模板化成员变量类型有条件地指定默认初始化

How to specify default initialization conditionally based on templated member variable type

我有一个模板化的 class,它使用 std::conditional 来确定特定成员变量的类型。但是,我还想根据该条件更改默认初始化行为(在 ctor 列表初始化中,或在成员声明本身中),因为其中一个选项是单例。 例如

#include <type_traits>

class NotSingleton{
public:
NotSingleton() = default;
};

class Singleton{
public:
static Singleton& getInstance(){
    static Singleton singleton;
    return singleton;
}
// delete copy ctor/assignment etc.
private:
Singleton() = default;
~Singleton() = default;
};

template<bool UseSingleton>
class MyClass{
public:
MyClass() {}

private:
std::conditional_t<UseSingleton, Singleton&, NotSingleton> m_member;
};

UseSingleton = true 时无法编译,因为 m_member 无法使用 Singleton 的默认构造函数。如果 UseSingleton = true?

如何设置 m_member 从 MultipleSubscriberListener::getInstance() 初始化
std::conditional_t<UseSingleton, Singleton&, NotSingleton> m_member =
    []() -> decltype(m_member) {
        if constexpr (UseSingleton)
            return Singleton::getInstance();
        else
            return {};
    }();

如果你不希望它成为默认初始化器,你也可以将它放在构造函数的成员初始化器列表中。

除了 lambda,您还可以使用成员函数,如果它看起来更清晰的话。在任何一种情况下,return 类型都应为 decltype(m_member),以便传递引用而不是衰减。

您也可以使用 decltype(auto),但是这样做可能会出现未定义的行为。如果您使用 decltype(auto) 并且不直接在 return statement 中构造 NotSingleton 对象(而不是从例如局部变量传递它),那么您将 return a悬挂引用,导致成员构造中的未定义行为。

在 c++20 中,您可以定义 2 个构造函数并添加要求:

MyClass() requires(UseSingleton)
: m_member(Singleton::getInstance())
{}

MyClass() requires(!UseSingleton)
{}