Fixed make_comparator metafunction
[libcds.git] / cds / opt / options.h
1 //$$CDS-header$$
2
3 #ifndef CDSLIB_OPT_OPTIONS_H
4 #define CDSLIB_OPT_OPTIONS_H
5
6 /*
7     Framework to define template options
8
9     Editions:
10         2011.01.23 khizmax  Created
11 */
12
13 #include <cds/details/aligned_type.h>
14 #include <cds/user_setup/allocator.h>
15 #include <cds/user_setup/cache_line.h>
16 #include <cds/algo/atomic.h>
17 #include <stdlib.h> // rand, srand
18
19 namespace cds {
20
21 /// Framework to define template options
22 /**
23     There are two kind of options:
24     - \p type-option - option that determines a data type. The template argument \p Type of the option is a type.
25     - \p value-option - option that determines a value. The template argument \p Value of the option is a value.
26 */
27 namespace opt {
28
29     /// Predefined options value (generally, for the options that determine the data types)
30     namespace v {}
31
32     /// Type indicates that an option is not specified and the default one should be used
33     struct none
34     {
35         //@cond
36         template <class Base> struct pack: public Base
37         {};
38         //@endcond
39     };
40
41     /// Metafunction for selecting default option value
42     /**
43         Template parameters:
44         - \p Option - option value
45         - \p Default - default option value
46         - \p Value - option value if \p Option is not opt::none
47
48         If \p Option is opt::none, the metafunction result is \p Default, otherwise
49         the result is \p Value.
50
51         Examples:
52         \code
53         // default_spin is cds::sync::spin
54         typedef typename cds::opt::select_default< cds::opt::none, cds::sync::spin >::type  default_spin;
55
56         // spin_32bit is cds::sync::reentrant_spin32
57         typedef typename cds::opt::select_default< cds::opt::none, cds::sync::reentrant_spin32 >::type  spin_32bit;
58         \endcode
59     */
60     template <typename Option, typename Default, typename Value = Option>
61     struct select_default
62     {
63         typedef Value type ;   ///< metafunction result
64     };
65     //@cond
66     template <typename Default>
67     struct select_default< none, Default >
68     {
69         typedef Default type;
70     };
71     //@endcond
72
73     /// Metafunction to select option value
74     /**
75         This metafunction is intended for extracting the value of the \p Option option.
76         For example,
77         \code
78         #include <cds/opt/options.h>
79         #include <type_traits> // only for testing purpose (static_assert)
80
81         struct tag_a;
82
83         // Define option
84         typedef cds::opt::tag< tag_a >  tag_option;
85
86         // What is the value of the tag_option?
87         // How we can extract tag_a from tag_option?
88         // Here is a solution:
89         typedef cds::opt::value< tag_option >::tag  tag_option_value;
90
91         // tag_option_value is the same as tag_a
92         static_assert( std::is_same< tag_option_value, tag_a >::value, "Error: tag_option_value != tag_a" );
93
94         \endcode
95     */
96     template <typename Option>
97     struct value: public Option::template pack<none>
98     {};
99
100
101     /// [type-option] Option setter specifies a tag
102     /**
103         Suppose, you have a struct
104         \code
105         struct Feature
106         {  .... };
107         \endcode
108         and you want that your class \p X would be derived from several \p Feature:
109         \code
110             class X: public Feature, public Feature
111             { .... };
112         \endcode
113
114         How can you distinguish one \p Feature from another?
115         You may use a tag option:
116         \code
117             template <typename Tag>
118             struct Feature
119             { .... };
120
121             class tag_a;
122             class tag_b;
123             class X: public Feature< tag_a >, public Feature< tag_b >
124             { .... };
125         \endcode
126         Now you can distinguish one \p Feature from another:
127         \code
128             X x;
129             Feature<tag_a>& fa = static_cast< Feature<tag_a> >( x );
130             Feature<tag_b>& fb = static_cast< Feature<tag_b> >( x );
131         \endcode
132
133         \p tag option setter allows you to do things like this for an option-centric approach:
134         \code
135         template <typename ...Options>
136         struct Feature
137         { .... };
138
139         class tag_a;
140         class tag_b;
141         class X: public Feature< tag<tag_a> >, public Feature< tag<tag_b> >
142         { .... };
143         \endcode
144
145         This option setter is widely used in cds::intrusive containers to distinguish
146         between different intrusive part of container's node.
147
148         An incomplete type can serve as a \p Tag.
149     */
150     template <typename Tag>
151     struct tag {
152         //@cond
153         template<class Base> struct pack: public Base
154         {
155             typedef Tag tag;
156         };
157         //@endcond
158     };
159
160     /// [type-option] Option setter specifies lock class
161     /**
162         Specification of the \p Type class is:
163         \code
164         struct Lock {
165             void lock();
166             void unlock();
167         };
168         \endcode
169     */
170     template <typename Type>
171     struct lock_type {
172         //@cond
173         template<class Base> struct pack: public Base
174         {
175             typedef Type lock_type;
176         };
177         //@endcond
178     };
179
180     /// [type-option] @ref cds_sync_monitor "Monitor" type setter
181     /**
182         This option setter specifyes @ref cds_sync_monitor "synchronization monitor"
183         for blocking container.
184     */
185     template <typename Type>
186     struct sync_monitor {
187         //@cond
188         template <class Base> struct pack : public Base
189         {
190             typedef Type sync_monitor;
191         };
192         //@endcond
193     };
194
195     /// [type-option] Back-off strategy option setter
196     /**
197         Back-off strategy used in some algorithm.
198         See cds::backoff namespace for back-off explanation and supported interface.
199     */
200     template <typename Type>
201     struct back_off {
202         //@cond
203         template <class Base> struct pack: public Base
204         {
205             typedef Type back_off;
206         };
207         //@endcond
208     };
209
210     /// [type-option] Option setter for garbage collecting schema used
211     /**
212         Possible values of \p GC template parameter are:
213         - cds::gc::HP - Hazard Pointer garbage collector
214         - cds::gc::DHP - Dynamic Hazard Pointer garbage collector
215         - cds::gc::none::GC - No garbage collector (not supported for some containers)
216     */
217     template <typename GC>
218     struct gc {
219         //@cond
220         template <class Base> struct pack: public Base
221         {
222             typedef GC gc;
223         };
224         //@endcond
225     };
226
227     /// [type-option] Option setter for an allocator
228     /**
229         \p Type is allocator with \p std::allocator interface. Default is value of macro CDS_DEFAULT_ALLOCATOR
230         that, in turn, is \p std::allocator.
231
232         The \p libcds containers actively use rebinding to convert an allocator of one type to another. Thus,
233         you may specify any valid type as std::allocator's template parameter.
234
235         See also opt::node_allocator
236     */
237     template <typename Type>
238     struct allocator {
239         //@cond
240         template <typename Base> struct pack: public Base
241         {
242             typedef Type allocator;
243         };
244         //@endcond
245     };
246
247     /// [type-option] Option setter for node allocator
248     /**
249         \p Type is allocator with \p std::allocator interface. Default is value of macro CDS_DEFAULT_ALLOCATOR
250         that, in turn, is \p std::allocator.
251
252         Many node-base containers require an allocator for maintaining data (container's node) and for internal use.
253         Sometimes, this types of allocator should be different for performance reason.
254         For example, we should like to allocate the node from a pool of preallocated nodes.
255         Such pool can be seen as the node allocator.
256
257         Usually, if a container supports \p opt::allocator and \p %opt::node_allocator options
258         and \p opt::node_allocator is not specified the \p %opt::allocator option is used for maintaining the nodes.
259
260         The \p libcds containers actively use rebinding to convert an allocator of one type to another. Thus,
261         you may specify any valid type as std::allocator's template parameter.
262     */
263     template <typename Type>
264     struct node_allocator {
265         //@cond
266             template <typename Base> struct pack: public Base
267             {
268                 typedef Type node_allocator;
269             };
270         //@endcond
271     };
272
273     /// [type-option] Option setter for item counting
274     /**
275         Some data structure (for example, queues) has additional feature for item counting.
276         This option allows to set up appropriate item counting policy for that data structure.
277
278         Predefined option \p Type:
279         - atomicity::empty_item_counter - no item counting performed. It is default policy for many
280             containers
281         - atomicity::item_counter - the class that provides atomically item counting
282         - opt::v::sequential_item_counter - simple non-atomic item counter. This item counter is not intended for
283             concurrent containers and may be used only if it is explicitly noted.
284
285         You may provide other implementation of atomicity::item_counter interface for your needs.
286
287         Note, the item counting in lock-free containers cannot be exact; for example, if
288         item counter for a container returns zero it is not mean that the container is empty.
289         Thus, item counter may be used for statistical purposes only.
290     */
291     template <typename Type>
292     struct item_counter {
293         //@cond
294         template <typename Base> struct pack: public Base
295         {
296             typedef Type item_counter;
297         };
298         //@endcond
299     };
300
301     namespace v {
302         /// Sequential non-atomic item counter
303         /**
304             This type of item counter is not intended for concurrent containers
305             and may be used only if it is explicitly noted.
306         */
307         class sequential_item_counter
308         {
309         public:
310             typedef size_t counter_type    ;  ///< Counter type
311         protected:
312             counter_type  m_nCounter ;      ///< Counter
313
314         public:
315             sequential_item_counter()
316                 : m_nCounter(0)
317             {}
318
319             /// Returns current value of the counter
320             counter_type    value() const
321             {
322                 return m_nCounter;
323             }
324
325             /// Same as \ref value() with relaxed memory ordering
326             operator counter_type() const
327             {
328                 return value();
329             }
330
331             /// Increments the counter. Semantics: postincrement
332             counter_type inc()
333             {
334                 return m_nCounter++;
335             }
336
337             /// Decrements the counter. Semantics: postdecrement
338             counter_type dec()
339             {
340                 return m_nCounter--;
341             }
342
343             /// Preincrement
344             counter_type operator ++()
345             {
346                 return inc() + 1;
347             }
348             /// Postincrement
349             counter_type operator ++(int)
350             {
351                 return inc();
352             }
353
354             /// Predecrement
355             counter_type operator --()
356             {
357                 return dec() - 1;
358             }
359             /// Postdecrement
360             counter_type operator --(int)
361             {
362                 return dec();
363             }
364
365             /// Resets count to 0
366             void reset()
367             {
368                 m_nCounter = 0;
369             }
370         };
371     } // namespace v
372
373     /// Special alignment constants for \ref cds::opt::alignment option
374     enum special_alignment {
375         no_special_alignment = 0,   ///< no special alignment
376         cache_line_alignment = 1    ///< use cache line size defined in cds/user_setup/cache_line.h
377     };
378
379     /// [value-option] Alignment option setter
380     /**
381         Alignment for some internal data of containers. May be useful to solve false sharing problem.
382         \p Value defines desired alignment and it may be power of two integer or predefined values from
383         \ref special_alignment enum.
384     */
385     template <unsigned int Value>
386     struct alignment {
387         //@cond
388         template <typename Base> struct pack: public Base
389         {
390             enum { alignment = Value };
391         };
392         //@endcond
393     };
394
395     //@cond
396     namespace details {
397         template <typename Type, unsigned int Alignment>
398         struct alignment_setter {
399             typedef typename cds::details::aligned_type< Type, Alignment >::type  type;
400         };
401
402         template <typename Type>
403         struct alignment_setter<Type, no_special_alignment> {
404             typedef Type type;
405         };
406
407         template <typename Type>
408         struct alignment_setter<Type, cache_line_alignment> {
409             typedef typename cds::details::aligned_type< Type, c_nCacheLineSize >::type  type;
410         };
411     } // namespace details
412     //@endcond
413
414     /// Special padding constants for \p cds::opt::padding option
415     enum special_padding {
416         no_special_padding = 0,   ///< no special padding
417         cache_line_padding = 1,   ///< use cache line size defined in cds/user_setup/cache_line.h
418
419         /// Apply padding only for tiny data of size less than required padding
420         /**
421             The flag means that if your data size is less than the casheline size, the padding is applyed.
422             Otherwise no padding will be applyed.
423
424             This flag is applyed for padding value:
425             \code
426             cds::opt::padding< cds::opt::cache_line_padding | cds::opt::padding_tiny_data_only >;
427             cds::opt::padding< 256 | cds::opt::padding_tiny_data_only >;
428             \endcode
429         */
430         padding_tiny_data_only = 0x80000000,
431
432         //@cond
433         padding_flags = padding_tiny_data_only
434         //@endcond
435     };
436
437     /// [value-option] Padding option setter
438     /**
439         The padding for the internal data of some containers. May be useful to solve false sharing problem.
440         \p Value defines desired padding and it may be power of two integer or predefined values from
441         \p special_padding enum.
442     */
443     template <unsigned int Value>
444     struct padding {
445         //@cond
446         template <typename Base> struct pack: public Base
447         {
448             enum { padding = Value };
449         };
450         //@endcond
451     };
452
453     //@cond
454     namespace details {
455         enum padding_vs_datasize {
456             padding_datasize_less,
457             padding_datasize_equal,
458             padding_datasize_greater
459         };
460
461         template < typename T, unsigned int Padding, bool NoPadding, padding_vs_datasize Relation, bool TinyOnly >
462         struct apply_padding_helper;
463
464         template <typename T, padding_vs_datasize Relation, bool TinyOnly >
465         struct apply_padding_helper < T, 0, true, Relation, TinyOnly >
466         {
467             struct type {
468                 T   data;
469             };
470             typedef void padding_type;
471         };
472
473         template <typename T, unsigned int Padding, bool TinyOnly >
474         struct apply_padding_helper < T, Padding, false, padding_datasize_equal, TinyOnly >
475         {
476             struct type {
477                 T   data;
478             };
479             typedef void padding_type;
480         };
481
482         template <typename T, unsigned int Padding, bool TinyOnly >
483         struct apply_padding_helper < T, Padding, false, padding_datasize_less, TinyOnly >
484         {
485             typedef uint8_t padding_type[Padding - sizeof( T )];
486             struct type {
487                 T data;
488                 padding_type pad_;
489             };
490
491         };
492
493         template <typename T, unsigned int Padding >
494         struct apply_padding_helper < T, Padding, false, padding_datasize_greater, false >
495         {
496             typedef uint8_t padding_type[Padding - sizeof( T ) % Padding];
497             struct type {
498                 T data;
499                 padding_type pad_;
500             };
501         };
502
503         template <typename T, unsigned int Padding >
504         struct apply_padding_helper < T, Padding, false, padding_datasize_greater, true >
505         {
506             struct type {
507                 T data;
508             };
509             typedef void padding_type;
510         };
511
512         template <typename T, unsigned int Padding >
513         struct apply_padding
514         {
515         private:
516             enum { padding = Padding & ~padding_flags };
517
518         public:
519             static CDS_CONSTEXPR const size_t c_nPadding =
520                 static_cast<unsigned int>(padding) == static_cast<unsigned int>(cache_line_padding) ? cds::c_nCacheLineSize :
521                 static_cast<unsigned int>(padding) == static_cast<unsigned int>(no_special_padding) ? 0 : padding;
522
523             static_assert( (c_nPadding & (c_nPadding - 1)) == 0, "Padding must be a power-of-two number" );
524
525             typedef apply_padding_helper< T,
526                 c_nPadding,
527                 c_nPadding == 0,
528                 sizeof( T ) < c_nPadding ? padding_datasize_less : sizeof( T ) == c_nPadding ? padding_datasize_equal : padding_datasize_greater,
529                 (Padding & padding_tiny_data_only) != 0
530             > result;
531
532             typedef typename result::type type;
533
534             typedef typename std::conditional<
535                 std::is_same< typename result::padding_type, void >::value,
536                 unsigned int,
537                 typename result::padding_type
538             >::type padding_type;
539         };
540
541     } // namespace details
542     //@endcond
543
544
545     /// [type-option] Generic option setter for statisitcs
546     /**
547         This option sets a type to gather statistics.
548         The option is generic - no predefined type(s) is provided.
549         The particular \p Type of statistics depends on internal structure of the object.
550     */
551     template <typename Type>
552     struct stat {
553         //@cond
554         template <typename Base> struct pack: public Base
555         {
556             typedef Type stat;
557         };
558         //@endcond
559     };
560
561     /// [type-option] Option setter for C++ memory model
562     /**
563         The <b>cds</b> library supports following memory ordering constraints for atomic operations in container implementation:
564         - \p v::relaxed_ordering - relaxed C++ memory model. This mode supports full set of memory ordering constraints:
565             \p memory_order_relaxed, \p memory_order_acquire, \p memory_order_release and so on.
566         - \p v::sequential_consistent - sequentially consistent C++ memory model (default memory ordering for C++). In
567             this mode any memory ordering constraint maps to \p memory_order_seq_cst.
568
569         The \p Type template parameter can be \p v::relaxed_ordering or \p v::sequential_consistent.
570
571         You may mix different memory ordering options for different containers: one declare as sequentially consistent,
572         another declare as relaxed.
573         Usually, \p v::relaxed_ordering is the default memory ordering for <b>libcds</b> containers.
574     */
575     template <typename Type>
576     struct memory_model {
577         //@cond
578         template <typename Base> struct pack: public Base
579         {
580             typedef Type memory_model;
581         };
582         //@endcond
583     };
584
585     namespace v {
586         /// Relaxed memory ordering model
587         /**
588             In this memory model the memory constraints are defined according to C++ Memory Model specification:
589             each constraint is mapped to \p std::memory_order constraints one-to-one
590
591             See \p opt::memory_model for explanations
592         */
593         struct relaxed_ordering {
594             //@cond
595             static const atomics::memory_order memory_order_relaxed    = atomics::memory_order_relaxed;
596             static const atomics::memory_order memory_order_consume    = atomics::memory_order_consume;
597             static const atomics::memory_order memory_order_acquire    = atomics::memory_order_acquire;
598             static const atomics::memory_order memory_order_release    = atomics::memory_order_release;
599             static const atomics::memory_order memory_order_acq_rel    = atomics::memory_order_acq_rel;
600             static const atomics::memory_order memory_order_seq_cst    = atomics::memory_order_seq_cst;
601             //@endcond
602         };
603
604         /// Sequential consistent memory ordering model
605         /**
606             In this memory model any memory constraint is equivalent to \p memory_order_seq_cst.
607
608             See \p opt::memory_model for explanations
609         */
610         struct sequential_consistent {
611             //@cond
612             static const atomics::memory_order memory_order_relaxed    = atomics::memory_order_seq_cst;
613             static const atomics::memory_order memory_order_consume    = atomics::memory_order_seq_cst;
614             static const atomics::memory_order memory_order_acquire    = atomics::memory_order_seq_cst;
615             static const atomics::memory_order memory_order_release    = atomics::memory_order_seq_cst;
616             static const atomics::memory_order memory_order_acq_rel    = atomics::memory_order_seq_cst;
617             static const atomics::memory_order memory_order_seq_cst    = atomics::memory_order_seq_cst;
618             //@endcond
619         };
620
621         //@cond
622         /// Totally relaxed memory ordering model (do not use!)
623         /**
624             In this memory model any memory constraint is equivalent to \p memory_order_relaxed.
625             @warning Do not use this model! It intended for testing purposes only
626             to verify debugging instruments like Thread Sanitizer.
627
628             See \p opt::memory_model for explanations
629         */
630         struct total_relaxed_ordering {
631             static const atomics::memory_order memory_order_relaxed    = atomics::memory_order_relaxed;
632             static const atomics::memory_order memory_order_consume    = atomics::memory_order_relaxed;
633             static const atomics::memory_order memory_order_acquire    = atomics::memory_order_relaxed;
634             static const atomics::memory_order memory_order_release    = atomics::memory_order_relaxed;
635             static const atomics::memory_order memory_order_acq_rel    = atomics::memory_order_relaxed;
636             static const atomics::memory_order memory_order_seq_cst    = atomics::memory_order_relaxed;
637         };
638         //@endcond
639     } // namespace v
640
641     /// [type-option] Base type traits option setter
642     /**
643         This option setter is intended generally for internal use for type rebinding.
644     */
645     template <typename Type>
646     struct type_traits {
647         //@cond
648         template <typename Base> struct pack: public Base
649         {
650             typedef Type type_traits;
651         };
652         //@endcond
653     };
654
655     /// Resizing policy option
656     /**
657         This option specifies the resizing policy that decides when to resize a container.
658         Used in some containers, for example, in container::StripedHashSet, intrusive::StripedHashSet.
659
660         The real resizing policy specified by \p Type does strongly depend on a container
661         that supports this option, see container documentation about possibly \p Type values.
662     */
663     template <typename Type>
664     struct resizing_policy {
665         //@cond
666         template <typename Base> struct pack: public Base
667         {
668             typedef Type resizing_policy;
669         };
670         //@endcond
671     };
672
673     /// Copy policy option
674     /**
675         The copy policy defines an item copying algorithm which is used, for example, when a container is resized.
676         It is very specific algorithm depending on type of the container.
677     */
678     template <typename Type>
679     struct copy_policy {
680         //@cond
681         template <typename Base> struct pack: public Base
682         {
683             typedef Type copy_policy;
684         };
685         //@endcond
686     };
687
688     /// Swap policy option
689     /**
690         The swap policy specifies an algorithm for swapping two objects.
691         Usually, the default policy is \p std::swap (see opt::v::default_swap_policy):
692
693         @code
694         struct std_swap {
695             template <typename T>
696             void operator ()( T& v1, T& v2 )
697             {
698                 std::swap( v1, v2 );
699             }
700         };
701         @endcode
702     */
703     template <typename Type>
704     struct swap_policy {
705         //@cond
706         template <typename Base> struct pack: public Base
707         {
708             typedef Type swap_policy;
709         };
710         //@endcond
711     };
712
713     namespace v {
714
715         /// Default swap policy (see opt::swap_policy option)
716         /**
717             The default swap policy is wrappr around \p std::swap algorithm.
718         */
719         struct default_swap_policy {
720             /// Performs swapping of \p v1 and \p v2 using \p std::swap algo
721             template <typename T>
722             void operator()( T& v1, T& v2 ) const
723             {
724                 std::swap( v1, v2 );
725             }
726         };
727     } // namespace v
728
729     /// Move policy option
730     /**
731         The move policy specifies an algorithm for moving object content.
732         In trivial case, it can be simple assignment.
733
734         The move interface is:
735         \code
736         template <typename T>
737         struct move_policy {
738             void operator()( T& dest, T& src );
739         };
740         \endcode
741
742         Note that in move algorithm the \p src source argument can be changed too.
743         So you can use move semantics.
744
745         Usually, the default move policy is opt::v::assignment_move_policy
746     */
747     template <typename Type>
748     struct move_policy {
749         //@cond
750         template <typename Base> struct pack: public Base
751         {
752             typedef Type move_policy;
753         };
754         //@endcond
755     };
756
757     namespace v {
758         /// \ref opt::move_policy "Move policy" based on assignment operator
759         struct assignment_move_policy
760         {
761             /// <tt> dest = src </tt>
762             template <typename T>
763             void operator()( T& dest, T const& src ) const
764             {
765                 dest = src;
766             }
767         };
768     } // namespace v
769
770     /// [value-option] Enable sorting
771     /**
772         This option enables (<tt>Enable = true</tt>) or disables (<tt>Enable == false</tt>)
773         sorting of a container.
774     */
775     template <bool Enable>
776     struct sort {
777         //@cond
778         template <typename Base> struct pack: public Base
779         {
780             static bool const sort = Enable;
781         };
782         //@endcond
783     };
784
785     /// [type-option] Concurrent access policy
786     /**
787         This option specifies synchronization strategy for fine-grained lock-based containers.
788         The option has no predefined \p Policy type.
789         For each container that accepts this option the range of available \p Policy types
790         is unique.
791     */
792     template <typename Policy>
793     struct mutex_policy {
794         //@cond
795         template <typename Base> struct pack: public Base
796         {
797             typedef Policy mutex_policy;
798         };
799         //@endcond
800     };
801
802
803     /// [type-option] Random number generator
804     /**
805         The option specifies a random number generator.
806         \p Random can be any STL random number generator producing
807         unsigned integer: \p std::linear_congruential_engine,
808         \p std::mersenne_twister_engine, \p std::subtract_with_carry_engine
809         and so on, or opt::v::c_rand.
810
811     */
812     template <typename Random>
813     struct random_engine {
814         //@cond
815         template <typename Base> struct pack: public Base
816         {
817             typedef Random random_engine;
818         };
819         //@endcond
820     };
821
822     namespace v {
823         /// \p rand() -base random number generator
824         /**
825             This generator returns a pseudorandom integer in the range 0 to \p RAND_MAX (32767).
826         */
827         struct c_rand {
828             typedef unsigned int result_type; ///< Result type
829
830             /// Constructor initializes object calling \p srand()
831             c_rand()
832             {
833                 srand(1);
834             }
835
836             /// Returns next random number calling \p rand()
837             result_type operator()()
838             {
839                 return (result_type) rand();
840             }
841         };
842     } // namespace v
843
844     //@cond
845     // For internal use
846     template <typename Accessor>
847     struct key_accessor {
848         template <typename Base> struct pack: public Base
849         {
850             typedef Accessor key_accessor;
851         };
852     };
853
854     template <typename Traits, typename ReplaceWith, typename WhatReplace = none >
855     struct replace_key_accessor {
856         typedef typename std::conditional<
857             std::is_same< typename Traits::key_accessor, WhatReplace >::value,
858             typename opt::key_accessor< ReplaceWith >::template pack< Traits >,
859             Traits
860         >::type type;
861     };
862     //@endcond
863
864 }}  // namespace cds::opt
865
866 #include <cds/opt/make_options_var.h>
867
868 #endif  // #ifndef CDSLIB_OPT_OPTIONS_H