仅为特定类型初始化 C++ 模板化 class 的成员

Initialze a member of a C++ templated class only for specific type

假设我有一个这样的模板 class:

template <typename C>
class ValArray
{
    ValArray() = default;
    ValArray(const ValArray&) = delete;

    C& operator[](size_t pos) { return _values[pos]; }
  ...
private:
    std::array<C, ARRAY_SIZE> _values;
};

这是用许多不同类型实例化的。我想做的是初始化 _values 只有 类型 bool 但不是其他类型。所以,如果我创建 ValArray<bool> val 那么我希望所有元素都是 false,例如:

std::array<bool, ARRAY_SIZE> _values = {false};

但是对于任何其他类型,我根本不想初始化_values

是否有一些我没能找到的模板魔法允许这样做?我希望不必为此创建一个单独的 class,因为这会级联到我必须创建专业化的许多其他地方。

在C++17及之后的版本中,可以在构造函数中使用if constexpr来赋值数组元素,eg:

template <typename C>
class ValArray
{
public:
    ValArray() {
        if constexpr (std::is_same_v<C, bool>) {
            _values.fill(false);
        }
    }

    ...

private:
    std::array<C, ARRAY_SIZE> _values;
};

Online Demo

如果Cbool,构造函数将被编译为:

ValArray() { _values.fill(false); }

否则编译为:

ValArray() {}

在 C++17 之前,您可以通过 std::enable_if 使用 SFINAE 完成同样的事情,例如:

template <typename C>
class ValArray
{
public:
    template<typename T = C, typename std::enable_if<std::is_same<T, bool>::value, int>::type = 0>
    ValArray() { _values.fill(false); }

    template<typename T = C, typename std::enable_if<!std::is_same<T, bool>::value, int>::type = 0>
    ValArray() { }
    
    // ...

private:
    std::array<C, ARRAY_SIZE> _values;
};

Online Demo

在如何做到这一点的方法中,您可以简单地在声明后为 class 成员添加专门化,例如:

template<> 
constexpr ValArray<bool>::ValArray() noexcept : _values({false}) {};

因为 ctor 是明确默认的,应该被移动,并且异常说明符应该在所有构造函数中保持一致:

template <typename C>
class ValArray
{
public:
    ValArray() noexcept;
    ValArray(const ValArray&) = delete;

    C& operator[](size_t pos) { return _values[pos]; }

private:
    std::array<C, ARRAY_SIZE> _values;
};

template<typename C>  ValArray<C>::ValArray() noexcept = default;
template<>  ValArray<bool>::ValArray() noexcept : _values({false}) {};

非常早期的 C++ 版本中提供了类似的专业化结构,在这种情况下不需要 SFINAE 或 if constexpr