How to use the default value in the template metaprogram

I had the following problem:

I have a generic container that can perform some type operations. Operations for simplicity, thread safe, on request. And , requested , means that the type in the container has typedef std::true_type needs_thread_safety; .

 struct thread_safe_item { typedef std::true_type needs_thread_safety; /* */ }; struct thread_unsafe_item { typedef std::false_type needs_thread_safety; /* */ }; template<typename TItem> container { /* some algorithms, that are std::enable_if selected, according to needs_thread_safety */ }; 

But I want needs_thread_safety be enabled and not need to be defined (= default false_type). I tried the following:

  struct thread_unsafe_item { /* */ }; template<typename TItem> struct thread_safety_selector { template<typename T> struct has_defined_thread_safety { typedef char yes[1]; typedef char no[2]; template <typename C> static yes& test(typename C::needs_thread_safety*); template <typename> static no& test(...); static const bool value = sizeof(test<T>(0)) == sizeof(yes); }; typedef typename std::conditional< has_defined_thread_safety<TItem>::value, typename TItem::needs_thread_safety, std::false_type >::type needs_thread_safety; }; .... struct <typename TItem> container { /* changed all TItem::needs_thread_safety selectors to thread_safety_selector<TItem>::needs_thread_safety */ }; 

But, apparently, no lazy evaluation occurs, since error error C2039: 'needs_thread_safety' : is not a member of 'thread_unsafe_item' .

How can I get the default value for an argument not specified?

This is for educational purposes, so I do not need another way to solve this problem.

Thanks!

+6
source share
3 answers

You cannot use std::conditional for this, since it will always parse all its arguments. You can create your own predicate:

 template <bool, class> struct get_thread_safety; template <class T> struct get_thread_safety<true, T> { typedef typename T::needs_thread_safety type; }; template <class T> struct get_thread_safety<false, T> { typedef std::false_type type; }; // Used like this: typedef typename get_thread_safety< has_defined_thread_safety<TItem>::value, TItem >::type needs_thread_safety; 
+7
source

In fact, this can be made a little easier by using std::enable_if in combination with std::conditional :

 #include <iostream> #include <type_traits> // Classes to be checked against needs_thread_safety struct A {}; struct B { typedef std::true_type needs_thread_safety; }; struct C { typedef std::false_type needs_thread_safety; }; // Checker helper template<class T> class get_thread_safety { typedef char(&zero_size_t)[0]; template <class X> static typename std::enable_if<X::needs_thread_safety::value, char>::type check(int); template <class X> static typename std::enable_if<!X::needs_thread_safety::value, zero_size_t>::type check(int); template <class X> static zero_size_t check(...); public: typedef typename std::conditional<sizeof(check<T>(0)), std::true_type, std::false_type>::type type; }; int main() { // Usage. Will print 0 1 0 std::cout << get_thread_safety<A>::type::value << std::endl; std::cout << get_thread_safety<B>::type::value << std::endl; std::cout << get_thread_safety<C>::type::value << std::endl; return 0; } 
+2
source

You can use std::conditional lazy way, you just need to avoid using a nested typedef inside its list of template options. You will also need another type of backup for the false case ("default", as you called it):

 template<typename TItem> struct thread_safety_selector { template<typename T> struct has_defined_thread_safety { typedef char yes[1]; typedef char no[2]; template <typename C> static yes& test(typename C::needs_thread_safety*); template <typename> static no& test(...); static const bool value = sizeof(test<T>(0)) == sizeof(yes); }; // this would be your "default value" struct not_thread_safe { typedef std::false_type needs_thread_safety; }; typedef typename std::conditional< has_defined_thread_safety<TItem>::value, TItem, // <---- note, not using the typedef here not_thread_safe >::type::needs_thread_safety needs_thread_safety; // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ // lazily, after the selection is done }; 
+1
source

All Articles