Как предотвратить специализацию std :: vector & lt; bool & gt;

У меня есть шаблонный класс, который имеет член типа данных std::vector<T>где T также является параметром моего шаблонного класса.

В моем шаблонном классе у меня есть некоторая логика, которая делает это:

T &value = m_vector[index];

Кажется, что это не компилируется, когда T является логическим значением, потому что оператор [] в std :: vector не возвращает bool-ссылку, а другой тип.

Некоторые альтернативы (хотя мне не нравится ни один из них):

  • скажите моим пользователям, что они не должны использовать bool в качестве параметра шаблона
  • есть специализация моего класса для bool (но это требует некоторого дублирования кода)

Разве нет способа сказать, что std :: vector не специализируется на bool?

11

Решение

Вы просто не можете иметь шаблонный код вести себя регулярно для 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 ключевые слова в коде выше, но это вводит многословие снова.

8

Другие решения

использование std::vector<char> вместо.

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 или похожие.

4

Есть способы предотвратить vector<bool> Специализация: Передача пользовательского распределителя.

std::vector<bool, myallocator> realbool;

В следующей статье есть некоторые детали:
https://www.informit.com/guides/content.aspx?g=cplusplus&SEQNUM = 98

Конечно, это требует, чтобы у вас был контроль над vector определения, так что это, вероятно, не совсем решение для вас. Кроме того, у него есть свои недостатки …

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), Поскольку тип данных больше не является логическим, специализация не выполняется.

В местах, где я теперь получаю элемент из вектора, я просто заменяю

m_internalVector[index]

от

m_internalVector[index].m_value

Но это кажется намного более элегантным, чем использование черт для замены bool на char, а затем использование приведений для преобразования между char и bool (и, возможно, переинтерпретация приведений для преобразования char& кипеть&).

Как вы думаете?

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;
};

Это может потребовать небольшой подстройки для ваших целей, но обычно это то, что я делаю в этих случаях.

1
По вопросам рекламы [email protected]