如何防止性病::载体<bool>的专业化

How to prevent specialization of std::vector<bool>

本文关键字:bool gt 专业化 何防止 lt 载体      更新时间:2023-10-16

我有一个模板化类,它有一个类型为std::vector<T>的数据成员,其中T也是我的模板化类的参数。

在我的模板类中,我有一些逻辑可以做到这一点:

T &value = m_vector[index];

当t是布尔值时,这似乎不会编译,因为std::vector的[]运算符不返回布尔引用,而是返回不同的类型。

一些替代方案(尽管我不喜欢其中任何一个(:

  • 告诉我的用户,他们不能使用bool作为模板参数
  • 让我的类专门用于bool(但这需要一些代码重复(

难道没有办法告诉std::vector不要专门针对bool吗?

如果数据由std::vector<bool>表示,那么模板化代码就不能使Tbool有规律地运行,因为CCD_4不是容器。正如@Mark Ransom所指出的,你可以使用std::vector<char>,例如通过像这样的特性

template<typename T> struct vector_trait { typedef std::vector<T> type; };
template<> struct vector_trait<bool> { typedef std::vector<char> type; };

然后在当前使用std::vector<T>的任何位置使用typename vector_trait<T>::type。这里的缺点是需要使用强制转换来从char转换为bool

在你自己的答案中建议的一个替代方案是编写一个具有隐式转换和构造函数的包装器

template<typename T>
class wrapper
{
public:
        wrapper() : value_(T()) {}
        /* explicit */ wrapper(T const& t): value_(t) {}
        /* explicit */ operator T() { return value_; }
private:
        T value_;
};

并且在任何地方都使用CCD_ 10而不必进行投射。然而,这也有缺点,因为包含真实bool参数的标准转换序列的行为与使用wrapper<bool>的用户定义转换不同(编译器最多可以使用1个用户定义转换,并根据需要使用尽可能多的标准转换(。这意味着带有函数重载的模板代码可能会微妙地中断。您可以在上面的代码中取消注释explicit关键字,但这再次引入了冗长性。

请改用std::vector<char>

以下内容适合您吗?

template <typename T>
struct anything_but_bool {
    typedef T type;
};
template <>
struct anything_but_bool<bool> {
    typedef char type;
};
template <typename T>
class your_class {
    std::vector<typename anything_but_bool<T>::type> member;
};

不那么轻率的是,anything_but_bool的名称可能应该是prevent_bool或类似的名称。

基于您的所有输入,我找到了一个更优雅的解决方案。

首先,我定义了一个包含一个成员的简单类。让我们称之为wrapperClass:

template <typename T>
class wrapperClass
   {
   public:
      wrapperClass() {}
      wrapperClass(const T&value) : m_value(value) {}
      T m_value;
   };

现在,我可以在模板类中定义我的std::vector,如下所示:

std::vector<wrapperClass<T>> m_internalVector;

由于sizeof(WrapperClass<bool>)也是1,所以我期望sizeof(WrapperClass<T>)将始终等于sizeof(T)。由于数据类型现在不再是布尔,因此不执行专门化。

在我现在从向量中获得元素的地方,我只需替换

m_internalVector[index]

通过

m_internalVector[index].m_value

但这似乎比使用traits将bool替换为char,然后使用强制转换在char和bool之间转换(可能还会重新解释强制转换以将char&转换为bool&(要优雅得多。

你觉得怎么样?

您可以使用自定义代理类来保存布尔。

class Bool
{
  public:
    Bool() = default;
    Bool(bool in) : value(in) {}
    Bool& operator=(bool in) {value = in;}
    operator bool() const& {return value;}
  private:
    bool value;
};

出于您的目的,这可能需要进行一些调整,但在这种情况下,我通常会这样做。

std::basic_string<bool> flags(flagCount, false);

从语义上讲,使用string很奇怪,但它的工作原理基本上与std::vector类似,使用指针/引用时的行为与预期一致,并且在传递到占用跨度的函数时,它可以方便地转换为std::span<bool>,不需要包装类或repret_cast(例如,使用CCD24会因为强制转换而使这些情况变得尴尬(。除非C++添加了一个std::bit_vector并反对专业化,否则我们没有太多好的选择。

有一种方法可以防止vector<bool>专门化:传递自定义分配器。

std::vector<bool, myallocator> realbool; 

以下文章提供了一些详细信息:https://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=98

当然,这需要您能够控制vector定义,所以它可能不是真正适合您的解决方案。除此之外,它本身也有一些缺点。。。