仅为特定类型初始化 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;
};
如果C
是bool
,构造函数将被编译为:
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;
};
在如何做到这一点的方法中,您可以简单地在声明后为 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
。
假设我有一个这样的模板 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;
};
如果C
是bool
,构造函数将被编译为:
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;
};
在如何做到这一点的方法中,您可以简单地在声明后为 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
。