Channels ▼
RSS

Open Source

Checking Concept Without Concepts in C++


Combining Checks to Form a Concept

Okay, so we've seen how we can check for individual member functions; now it's time to combine the individual checks into a whole concept check. This is relatively straightforward to do: Just combine all the traits together:


template<typename T>
struct is_lockable:
    std::integral_constant<bool,
        std::is_class<T>::value &&
        has_lock_member_function<T>::value &&
        has_unlock_member_function<T>::value &&
        has_try_lock_member_function<T>::value>
{};

You can then use this combined concept test just as you would any other concept test, including using it with enable_if.

For example, the Boost Library provides a set of function templates named lock. One set matches the C++0x std::lock function, and takes a number of lockable objects; when it returns all the supplied lockable objects have been locked. This is done in a way that avoids deadlock if the same set of lockable objects is locked on another thread in any order.

The second form of boost::lock takes a pair of iterators pointing to lockable objects, and locks every element in the supplied range using a similar algorithm. This means that there are two overloads of boost::lock that take two identical parameters -- one that accepts two lockable objects, and one that takes two iterators.

Our is_lockable concept can thus be used with enable_if to distinguish between these cases:


    template<typename M1,typename M2>
    typename std::enable_if<
        is_lockable<M1>::value &&
        is_lockable<M2>::value,void>::type
    lock(M1& m1,M2& m2)
    {
        // nifty deadlock-free lock algorithm
    }

    template<typename Iterator>
    typename std::enable_if<!is_lockable<Iterator>::value,void>::type
    lock(Iterator begin,Iterator end)
    {
        // nifty deadlock-free lock algorithm for a range
    }

Conclusion

One of the key features of the C++0x template facility was the ability to specify requirements on the functions that must be available on a type in order to match a concept, and to overload functions to provide different implementations based on whether or not a type matched a type. In this article, I've demonstrated that a limited form of this is available without a special Concepts language feature, and shown how this can be used to write concepts and overload on them.

Source Code


#ifndef IS_LOCKABLE_HPP
#define IS_LOCKABLE_HPP
#include <type_traits>

typedef char small_type;
struct large_type
{
    small_type dummy[2];
};

template<typename T>
struct class_has_lock_member_function_returning_void_with_no_params
{
    template<void (T::*)()> struct tester;

    template<typename U>
    static small_type has_matching_member(tester<&U::lock>*); // A
    template<typename U>
    static large_type has_matching_member(...); // B
    
    static const bool value=sizeof(has_matching_member<T>(0))==sizeof(small_type);
};

template<typename T>
struct class_has_unlock_member_function_returning_void_with_no_params
{
    template<void (T::*)()> struct tester;

    template<typename U>
    static small_type has_matching_member(tester<&U::unlock>*); // A
    template<typename U>
    static large_type has_matching_member(...); // B
    
    static const bool value=sizeof(has_matching_member<T>(0))==sizeof(small_type);
};

template<typename T>
struct class_has_try_lock_member_function_returning_bool_with_no_params
{
    template<bool (T::*)()> struct tester;

    template<typename U>
    static small_type has_matching_member(tester<&U::try_lock>*); // A
    template<typename U>
    static large_type has_matching_member(...); // B
    
    static const bool value=sizeof(has_matching_member<T>(0))==sizeof(small_type);
};

template<typename T,bool is_class_type=std::is_class<T>::value>
struct has_lock_member_function:
    std::false_type
{};

template<typename T>
struct has_lock_member_function<T,true>:
    std::integral_constant<bool,
    class_has_lock_member_function_returning_void_with_no_params<T>::value>
{};

template<typename T,bool is_class_type=std::is_class<T>::value>
struct has_unlock_member_function:
    std::false_type
{};

template<typename T>
struct has_unlock_member_function<T,true>:
    std::integral_constant<bool,
        class_has_unlock_member_function_returning_void_with_no_params<T>::value>
{};

template<typename T,bool is_class_type=std::is_class<T>::value>
struct has_try_lock_member_function:
    std::false_type
{};

template<typename T>
struct has_try_lock_member_function<T,true>:
    std::integral_constant<bool,
        class_has_try_lock_member_function_returning_bool_with_no_params<T>::value>
{};


template<typename T>
struct is_lockable:
    std::integral_constant<bool,
        std::is_class<T>::value &&
        has_lock_member_function<T>::value &&
        has_unlock_member_function<T>::value &&
        has_try_lock_member_function<T>::value>
{};


#endif

References

BOOST_STATIC_ASSERT documentation.

Boost::enable_if documentation

Compiler support for C++0x features including static_assert

std::enable_if documentation for Microsoft Visual Studio

Boost Concept Check Library


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video