Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use 'default' value within template metaprogramming

I'm facing following problem:

I have some generic container, that is able to do some operations on types. The operations are, for simplicity, thread safe, when requested to. And, requested to means that the type in 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 the needs_thread_safety to be opt-in, and not needed to be defined (= default false_type). I've tried 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 there is apparently no lazy-evaluation going on, as the error is error C2039: 'needs_thread_safety' : is not a member of 'thread_unsafe_item'.

How can I achieve default value for the argument not specified?

It is for educational purposes, so I don't need different way how to solve this problem.

Thanks!

like image 400
nothrow Avatar asked Feb 06 '14 12:02

nothrow


1 Answers

You can't use std::conditional for that, as that will always parse all of 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;
like image 167
Angew is no longer proud of SO Avatar answered Sep 27 '22 23:09

Angew is no longer proud of SO