2015-10-06 2 views
0

Неправильной поддержка летучих квалифицированных перегрузок функций членов в STL предотвращает использование контейнеров, смарт-указателей и т.д. в общем виде. Скажем, я хочу объявить класс-оболочку, которая обеспечивает семантику значений и позволяет неполнота базового типа:Правильной поддержка летучего классификатора функций-членов в STL

#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() и т. Д.

Он полностью предотвращает использование объектов STL (не связанный с оператором const_cast) в общем коде, который использует квалификатор функции-члена .

Какая причина таких плохих STL расчетное решение? Почему volatile спецификатор функции участника не поддерживается должным образом в STL ?? Is volatile Определитель функции функции лишен?

+0

Надеюсь, вы не предполагаете, что 'std :: container :: push_back' должен был быть' volatile', потому что это, безусловно, не должно было быть. – Mehrdad

+0

@Mehrdad Я оправдываю ваши ожидания.Я просто хочу знать, почему 'std :: container :: push_back() volatile' перегрузка наряду с' std :: container :: push_back() 'широко недоступна в STL? – Orient

+0

Зачем это было? Если это полезно, вы добавляете материал в API. Каков ваш прецедент для 'volatile std :: vector '? – Mat

ответ

1

Это очень хорошее решение. Это потому, что волатильность будет совершенно неправильная для большинства типов.

Имейте в виду, что 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.

+0

Является ли 'volatile dword' также UB? Как насчет 'std :: vector '? – Orient

+0

@Orient: что такое 'dword' и что такое' std :: variant'? Можете ли вы связать меня с их определениями? Я не видел их на C++. – Mehrdad

+0

dword означает здесь двойное слово (слово == ширина шины данных). Во втором я имею в виду 'std :: vector' (любой контейнер, http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4542.pdf также подходит). – Orient

0

«Плохое дизайнерское решение»? На самом деле, нет. Ключевое слово унаследовано от C, но сегодня для него очень мало пользы. Это не активно осуждает, но его основное использование - в простых случаях. Хорошим примером может служить аппаратное обеспечение с отображением памяти. Но не будет отображаемого в памяти std::deque<>, поэтому для поддержки STL мало смысла.

Смежные вопросы