Предговор
Представете си, че имам шаблон: template<class... Opts> class rqueue
, който може да има различни функции, избрани чрез тагове (структури със специални опции), предадени към списъка с параметри, напр.
rqueue<trace_record, opt::fixed_size<>> trace;
rqueue<trace_record::flat, opt::fixed_size<>, opt::virtual_offset<>> info;
Първата версия (trace
) е опашка от записи, която да се използва за записване на записите за проследяване (opt::fixed_size
ограничава размера си до 4096B). Втората версия (info
) ще бъде запълнена от първата (от някаква нишка, която ще пренапише записите с преобразуване в плоско представяне), но важното е, че opt::virtual_offset<>
, което добавя тези методи:
off_t start(); // virtual offset of oldest record
off_t stop(); // virtual offset of future record (when next gets written)
и различни други характеристики (offset_to_iterator()
), базирани на това виртуално отместване, което винаги нараства (с всеки запис), което симулира виртуална памет с размер напр. 4 GB (когато unsigned
се използва като отместване, може да бъде дори по-голямо с size_t
или unisgned long long
), където действителният буфер (с размер напр. 4096B) създава прозорец вътре в тази виртуална памет.
Връзка към друг мой свързан въпрос - помощник за пакет опции който е специално проектиран за този шаблон.
(Имайте предвид, че вероятно има много други функции, които могат да се комбинират независимо, напр. opt::rqueue_listener
, които могат да се използват за докладване на различни събития).
Проблемът
Успях да създам този шаблон с всички възможни функции, където някои методи са фиктивни, когато функцията не е избрана (напр. start()
връща нула и stop()
е същото като size()
в този случай), но аз бих искал да скрия методите по някакъв начин, ако функцията не е избрана. Някаква идея?
(Друг пример би бил фиктивно set_listener(void*)
, ако opt::rqueue_listener
не е включено - опцията може да се комбинира с всяка друга опция.)
РЕДАКТИРАНЕ: Представете си напр. using off_t = conditional_t<something,the_type,void>
и private: off_t start_()
. Това, което искам е да:
- Накарайте
public: off_t start()
да се обади на товаstart_()
, акоoff_t
не еvoid
- Няма метод
start()
, акоoff_t
е невалиден (или е изпълнено някакво условие). Като алтернатива някоиstatic_assert
, ако се опитам да го извикам.
Моите опити
Мислех да слея класа с разширители, които ще публикуват функциите, като се прехвърлят (*this
) към реалния клас (rqueue<...>&
) и пренасочват извикванията там (към частни методи, където разширителят става приятел). Създадох друг template<class... Bases> class merge
помощник, който може да наследи всеки избран клас, като същевременно игнорира всички void
предадени. Получи се, но решението е доста кофти, не ми харесва.
Друго възможно решение, което ми мина през ума, беше да създам някаква основна реализация (като различен шаблон, вероятно скрит в някои namespace detail
) и да използвам верига от специализации на шаблони, които ще публикуват методите въз основа на опциите. Проблемът е, че броят на комбинациите нараства бързо и може да има друг проблем с friend
-ing на класа, за да има достъп до частни методи на записа (първият параметър, предаден на шаблона).
Моите опити за SFINAE и static_assert
често завършваха с грешки на компилатора, оплаквайки се, че специализацията на метода не е разрешена в шаблони (или частични специализации) или static_assert се задейства, когато не трябва. Очаквам да има някакво хубаво решение. Очакваме с нетърпение да го видим :)
fill_empty
приема два параметъра - тип и стойност:template <class T, T V> struct fill_empty: tag::fill_empty { typedef T type; static constexpr T value = V; };
- person firda   schedule 13.10.2014start()
членска функция, но искаш тя да извикваvirtual_offset<>::start()
, когато класът ти наследява отvirtual_offset<>
, в противен случай да бъде недостъпна? - person Piotr Skotnicki   schedule 13.10.2014public: off_t start()
, акоopt::virtual_offset<...>
не е включен (off_t
може да получи всичко в този случай, моятopt::bind
ще ви помогне да го дефиниратеvoid
, ако имате нужда). - person firda   schedule 13.10.2014virtual
, това еtemplate
проектирано да бъде многоlight-weight
, ако не е включена специална функция (напр.rqueue<trace_record>
ще бъде основният, без допълнителни данни и методи). - person firda   schedule 13.10.2014static_assert(!std::is_same<off_t, void>::value, "!");
в публичнатаstart()
членска функция не е опция? - person Piotr Skotnicki   schedule 13.10.2014static_assert
. Трябва да съм работил твърде много последния път, за да пропусна това просто решение :D - person firda   schedule 13.10.2014