Неправильная поддержка летучая квалификация перегрузки функций-членов в СТЛ предотвращает использование контейнеров, умных указателей и т. д. в общем виде. Скажем, я хочу объявить класс-оболочку, который обеспечивает семантику значений и допускает неполноту базового типа:
#include <type_traits>
#include <utility>
#include <memory>
template< typename type >
struct recursive_wrapper
{
using value_type = type;
template< typename ...arguments >
recursive_wrapper(arguments &&... _arguments)
: storage_(std::make_unique< type >(std::forward< arguments >(_arguments)...))
{ ; }
operator type & () & noexcept
{
return *storage_;
}
operator type const & () const & noexcept
{
return *storage_;
}
operator type && () && noexcept
{
return std::move(*storage_);
}
operator type const && () const && noexcept
{
return std::move(*storage_);
}
operator volatile type & () volatile & noexcept
{
return *storage_;
}
operator volatile type const & () volatile const & noexcept
{
return *storage_;
}
operator volatile type && () volatile && noexcept
{
return std::move(*storage_);
}
operator volatile type const && () volatile const && noexcept
{
return std::move(*storage_);
}
private :
std::unique_ptr< type > storage_;
};
// file:main.cpp
#include <iostream>
#include <vector>
#include <cstdlib>
int
main()
{
struct A;
struct B { recursive_wrapper< A > a; };
struct A { std::vector< B > b; };
{ // basic usage
B b;
A & a = b.a; // OK
static_cast< void >(a);
}
// let's add cv-qualifiers
{
volatile B b;
volatile A & a = b.a; // error!
static_cast< void >(a);
}
return EXIT_SUCCESS;
}
Отсутствие подходящего летучая квалификация перегрузка std::unqie_ptr::operator * ()
вызывает ошибку:
main.cpp:38:16: error: indirection requires pointer operand ('volatile std::unique_ptr<A>' invalid)
return *storage_;
^~~~~~~~~
main.cpp:83:30: note: in instantiation of member function 'recursive_wrapper<A>::operator volatile A &' requested here
volatile A & a = b.a;
^
1 error generated.
Та же история WRT std::container::push_back()
, size()
, так далее.
Это полностью предотвращает использование объектов СТЛ (не включая const_cast
оператор) в общем коде, который использует volatile
квалификатор функции-члена.
В чем причина такого бедного СТЛ дизайнерское решение? Зачем volatile
Спецификатор функции-члена не поддерживается должным образом в СТЛ?? Является volatile
функция-член ограничена?
Это очень хорошо решение. Это потому, что волатильность будет совершенно неправильно для большинства типов.
Имейте в виду, что volatile
на объекте значит поля объекта могут изменяться спонтанно.
Рассмотрим следующее и предположим, что система гарантирует, что в любой данный момент begin
а также end
будет указывать на тот же блок памяти:
template<class T>
class vector
{
T *begin;
T *end;
vector(vector const volatile &other) : begin(other.begin), end(other.end) { ... }
};
Оказывается vector::vector(vector const volatile &)
является неправильно, потому что это не может гарантировать, что begin
а также end
читаются одновременно.
Следовательно, создаваемая им копия может иметь begin
а также end
которые не синхронизированы, хотя оригинал был полностью в порядке.
Я думаю, этого должно быть достаточно, чтобы вы поняли, почему volatile
едва используется.
Он просто не используется по той же причине, что вы, вероятно, ожидали использовать (то есть атомарность).
Его сценарий использования совершенно другой и необычный, и это не то, что вы бросаете по прихоти, как с const
,
«Плохое дизайнерское решение»? На самом деле, нет. Ключевое слово унаследовано от C, но сегодня оно очень мало используется. Это не активно осуждается, но его основное использование в простых случаях. Аппаратная часть памяти будет хорошим примером. Но не будет отображено в памяти std::deque<>
так что в поддержке STL нет особого смысла.