Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly use tag dispatching to pick a constructor

I'm trying to implement a set of mutex and lock classes for an embedded system. I've never used tag dispatching before, and I'm not sure if I'm doing it right. The description included in the boost documentation simply has this:

struct input_iterator_tag { };

and uses it to pick a specialized template function. I don't have a template, I just want to pick a specific constructor based on the presence of a tag:

// in mutex.h:

struct TryLock { };
// defined nowhere, i.e. there's no cpp file for this:
extern TryLock try_lock; 

template<typename MutexType>
class ScopedLock
{
  public:
    ScopedLock(MutexType& mtx) : m_mtx(mtx), m_acquired(true)
    {
      m_mtx.lock();
    }
    ScopedLock(MutexType& mtx, TryLock) : m_mtx(mtx)
    {
      m_acquired = m_mtx.tryLock();
    }
  ...
}

and somewhere in my code I have a mutex which I want to lock:

Mutex mtx;
ScopedLock<Mutex> lock(mtx, try_lock);

This compiles fine and works. I'm just curious if I can get rid of the extern TryLock try_lock;, as I have the impression that it's somewhat superfluous.

like image 696
Christoph Avatar asked Dec 25 '13 17:12

Christoph


People also ask

What is tag dispatching?

Tag dispatching is a way of using function overloading to dispatch based on properties of a type, and is often used hand in hand with traits classes. A good example of this synergy is the implementation of the std::advance() function in the C++ Standard Library, which increments an iterator n times.

What is TAG CPP?

Once HeaderDoc encounters an @class tag (with accompanying class declaration) in a C++ header, it treats all comments and declarations that follow (until the end of the class declaration) as belonging to that class, rather than to the header as a whole.


1 Answers

You won't need the extern declaration for try_lock, if you replace its usage in the lock constructor call with a temporary:

Mutex mtx;
ScopedLock<Mutex> lock(mtx, TryLock());

Otherwise the compiler will pass a copy of try_lock to your constructor, at which point it will want to link against it.

When the standard library needs to do this, it uses constexpr:

struct piecewise_construct_t { };
constexpr piecewise_construct_t piecewise_construct = piecewise_construct_t();
like image 196
razeh Avatar answered Nov 14 '22 23:11

razeh