Как предотвратить специализацию std::vector <bool>
У меня есть шаблонный класс, у которого есть член данных типа std::vector<T>
, где T также является параметром моего шаблонного шаблона.
В моем классе шаблона я имею довольно некоторую логику, которая делает это:
T &value = m_vector[index];
Это не похоже на компиляцию, когда T является логическим, потому что оператор [] из std::vector не возвращает ссылку bool, а другой тип.
Некоторые альтернативы (хотя мне они не нравятся):
- сообщите моим пользователям, что они не должны использовать bool в качестве параметра шаблона
- имеют специализацию моего класса для bool (но для этого требуется некоторое дублирование кода)
Не существует способа рассказать std::vector не специализироваться на bool?
Ответы
Ответ 1
Вы просто не можете регулярно менять шаблонный код для 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
в приведенном выше коде, но это снова добавляет многословие.
Ответ 2
Используйте std::vector<char>
вместо этого.
Ответ 3
Будет ли следующая работа для вас?
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
Вы можете использовать собственный класс прокси для хранения 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
Я нашел еще более элегантное решение, основанное на всех ваших вводах.
Сначала я определяю простой класс, содержащий один элемент. Позвольте называть это 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
Но это кажется намного более элегантным, чем использование черт для замены bool на char, а затем с помощью преобразований между char и bool (и, вероятно, переинтерпретировать приведения для преобразования char & в bool &).
Как вы думаете?
Ответ 6
Существуют способы предотвращения специализации vector<bool>
: передача пользовательского распределителя.
std::vector<bool, myallocator> realbool;
В следующей статье приведены некоторые детали:
https://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=98
Конечно, это требует, чтобы вы контролировали определения vector
, поэтому, вероятно, это не решение для вас. Кроме того, у него также есть некоторые недостатки его собственных...