如何防止std :: vector <bool> </bool>的专业化

时间:2013-01-17 17:37:40

标签: c++ templates vector boolean specialization

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

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

T &value = m_vector[index];

当T是布尔值时,似乎没有编译,因为std :: vector的[]运算符不返回bool-reference,而是返回不同的类型。

一些替代品(虽然我不喜欢其中任何一种):

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

有没有办法告诉std :: vector不要专门用于bool?

6 个答案:

答案 0 :(得分:8)

如果您的数据由T表示,那么bool等于std::vector<bool>,您根本无法定期模板化代码,因为这不是容器。正如@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; };

,然后在当前使用typename vector_trait<T>::type的任何地方使用std::vector<T>。这里的缺点是您需要使用强制转换从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_;
};

并在任何地方使用std::vector< wrapper<bool> >而无需投射。但是,这也有缺点,因为包含真实bool参数的标准转换序列的行为与用wrapper<bool>的用户定义转换不同(编译器最多可以使用1个用户定义的转换,并且必要时进行标准转换)。这意味着具有函数重载的模板代码可以巧妙地中断。您可以取消注释上面代码中的explicit关键字,但会再次引入详细信息。

答案 1 :(得分:4)

改为使用std::vector<char>

答案 2 :(得分:4)

以下是否适合您?

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

答案 3 :(得分:1)

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

std::vector<bool, myallocator> realbool; 

以下文章有一些细节: https://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=98

当然,这要求您可以控制vector定义,因此它可能不适合您。除此之外,它还有一些缺点......

答案 4 :(得分:1)

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

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

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

  private:
    bool value;
};

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

答案 5 :(得分:1)

我根据您的所有输入找到了更优雅的解决方案。

首先,我定义一个包含一个成员的简单类。我们称之为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替换bool更加优雅,然后使用强制转换来转换char和bool(并且可能重新解释转换以将char&amp;转换为bool&amp;)。

您怎么看?