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