c++ 如何防止std::vector的专门化< bool>

yws3nbqq  于 2023-02-14  发布在  其他
关注(0)|答案(7)|浏览(394)

我有一个模板类,它有一个std::vector<T>类型的数据成员,其中T也是我的模板类的一个参数。
在我的模板类中,我有相当多的逻辑可以做到这一点:

T &value = m_vector[index];

当T是一个布尔值时,这似乎无法编译,因为std::vector的[]操作符没有返回一个布尔值引用,而是返回一个不同的类型。
一些替代品(虽然我不喜欢他们中的任何一个):

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

有没有办法告诉std::vector不要专门处理bool?

alen0pnh

alen0pnh1#

如果你的数据是用std::vector<bool>表示的,那么你就不能让模板化的代码在T等于bool的情况下正常工作,因为这不是一个容器。

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
您自己的答案中建议的另一种方法是编写一个具有隐式转换和构造函数的 Package 器

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

并且在任何地方都使用std::vector< wrapper<bool> >,而不必强制转换。但是,这样做也有缺点,因为包含实bool参数的标准转换序列的行为与使用wrapper<bool>的用户定义转换不同(编译器最多可以使用1个用户定义转换,和尽可能多的标准转换)。这意味着带有函数重载的模板代码可能会微妙地中断。您可以取消注解上面代码中的explicit关键字,但这又会引入冗长。

9jyewag0

9jyewag02#

请改用std::vector<char>

polkgigr

polkgigr3#

下面的方法对你有用吗?

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或类似的名称。

mrwjdhj3

mrwjdhj34#

我发现了一个更优雅的解决方案,基于你所有的输入。
首先我定义了一个简单的类,它包含一个成员,我们将其命名为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),因为数据类型现在不再是bool,所以不执行专门化。
在从向量中得到元素的地方,我只需要替换

m_internalVector[index]

作者

m_internalVector[index].m_value

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

hwamh0ep

hwamh0ep5#

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

class Bool
{
  public:
    Bool() = default;
    Bool(bool in) : value(in) {}

    Bool& operator=(bool in) {value = in;}
    operator bool() const& {return value;}

  private:
    bool value;
};

为了您的目的,这可能需要一些调整,但这通常是我在这些情况下所做的。

xxslljrj

xxslljrj6#

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

从语义上讲,使用string很奇怪,但它的工作原理基本上与std::vector类似,其指针/引用的行为与预期一致,并且在传递给接受span的函数时,它可以方便地转换为std::span<bool>。不需要 Package 类或reinterpret_cast(例如,使用std::vector<uint8_t>会因为强制类型转换而使这些情况很尴尬).除非C++添加std::bit_vector并弃用专门化,否则我们没有太多好的选择.

hwamh0ep

hwamh0ep7#

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

std::vector<bool, myallocator> realbool;

下面的文章有一些细节:https://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=98
当然,这需要您能够控制vector的定义,因此它可能并不适合您。除此之外,它也有自己的一些缺点...

相关问题