Preface
Imagine I have a template: template<class... Opts> class rqueue
, which can have various features selected by tags (special options structures) passed to the parameter list, e.g.
rqueue<trace_record, opt::fixed_size<>> trace;
rqueue<trace_record::flat, opt::fixed_size<>, opt::virtual_offset<>> info;
The first version (trace
) is a record queue to be used for writing the trace records (the opt::fixed_size
limits its size to 4096B). The second version (info
) will get filled from the first one (by some thread, that will rewrite the records with conversion to flat representation), but the important thing is that opt::virtual_offset<>
which adds these methods:
off_t start(); // virtual offset of oldest record
off_t stop(); // virtual offset of future record (when next gets written)
and various other features (offset_to_iterator()
) based on this virtual offset that is always growing (with each record), which simulates virtual memory of size e.g. 4 GB (when unsigned
used as the offset, it could be even larger with size_t
or unisgned long long
), where the actual buffer (of size e.g. 4096B) creates a window inside that virtual memory.
Link to my other related question - option pack helper which was specifically designed for this template.
(Note that thare are possibly many other features that can be independently combined, e.g. opt::rqueue_listener
that can be used to report various events).
The Problem
I have managed to create that template with all the possible features, where some methods are dummy when the feature was not selected (e.g. start()
is returning zero and stop()
is same as size()
in that case), but I would like to hide the methods somehow, if the feature was not selected. Any idea?
(Another example would be dummy set_listener(void*)
if the opt::rqueue_listener
was not included - the option can be combined with any other option.)
EDIT: Imagine e.g. using off_t = conditional_t<something,the_type,void>
and private: off_t start_()
. What I want is to:
- Have
public: off_t start()
calling thatstart_()
ifoff_t
is notvoid
- Have no method
start()
ifoff_t
is void (or some condition met). Alternatively somestatic_assert
if I try to call it.
My Attempts
I was thinking about merging the class with extenders that would publish the functions by casting itself (*this
) to the real class (rqueue<...>&
) and redirecting the calls there (to private methods, where the extender is made a friend). I have created another template<class... Bases> class merge
helper that could inherit any class selected while ignoring any void
passed. It worked, but the solution is quite ugly, I don't like it.
Another possible solution that crossed my mind was to create some basic implementation (as a different template, possibly hidden in some namespace detail
) and use a chain of template specializations that would publish the methods based on the options. Problem is that the number of combinations is growing rapidly and there could be another problem with friend
-ing the class to have access to private methods of the record (first parameter passed to the template).
My SFINAE and static_assert
attempts often ended with compiler errors, complaining that method specialization is not allowed in templates (or partial specializations) or the static_assert got fired when it should not. I expect there is some nice solution. Looking forward to see it :)