Compile error while using boost::concept_check to check a template argument

123 Views Asked by At

I'm trying to compile a simple example of using a little bridge template externally_locked that is enable to control access to a BankAccount only after locking its parent AccountManager object. (refer to boost synchronization)

#include <boost/concept_check.hpp>

template <typename T, typename Lockable>
// Use a little bridge template externallly_locked that controls access to a BankAccount
class externally_locked {
    // This macro is used to check that a given template parameter meets certain requirements of
    // has certain properties
BOOST_CONCEPT_ASSERT((boost::LockableConcept<Lockable>));

public:
    externally_locked(T & obj, Lockable & lockable): obj_(obj), lockable_(lockable) {}

    externally_locked(Lockable& lockable): obj_(), lockable_(lockable) {}

   void set(const T& obj, Lockable& lockable) {
      obj_ = obj;
      lockable_ = lockable;
   }

private:
   T obj_;
   Lockable & lockable_;
};

Then get the following error:

root@34b558e548b5:/mnt/boost_threads# g++ -ggdb -pedantic  -Wall -Werror -O0 --save-temps bankmanager.cpp -o bankmanager
bankmanager.cpp:8:90: error: '*' cannot appear in a constant-expression
bankmanager.cpp:8:91: error: a call to a constructor cannot appear in a constant-expression
bankmanager.cpp:8:4: error: template argument 1 is invalid
BOOST_CONCEPT_ASSERT((boost::LockableConcept<Lockable>));
    ^
bankmanager.cpp:8:13: error: template argument 1 is invalid
BOOST_CONCEPT_ASSERT((boost::LockableConcept<Lockable>));

What needs to be fixed?

1

There are 1 best solutions below

0
sehe On BEST ANSWER

The name of the concept is not up-to-date with the Boost Thread source code. It probably needs to be BasicLockable (or any more specific [standard] or extended concept, if applicable).

To avoid confusion, let's rename the macro parameter:

template <typename T, typename LockableT>
// Use a little bridge template externallly_locked that controls access to a BankAccount
class externally_locked {
    // This macro is used to check that a given template parameter meets certain requirements of
    // has certain properties
    BOOST_CONCEPT_ASSERT((boost::BasicLockable<LockableT>));

  public:
    externally_locked(T& obj, LockableT& lockable) : obj_(obj), lockable_(lockable) {}

    externally_locked(LockableT& lockable) : obj_(), lockable_(lockable) {}

    void set(T const& obj, LockableT& lockable) {
        obj_      = obj;
        lockable_ = lockable;
    }

  private:
    T          obj_;
    LockableT& lockable_;
};

See it Live On Coliru

#include <boost/concept_check.hpp>
#include <boost/thread.hpp>
#include <boost/thread/lockable_adapter.hpp>
#include <boost/thread/lockable_concepts.hpp>
#include <boost/thread/strict_lock.hpp>

static bool some_condition() { return rand() % 2; }

// Use a little bridge template externallly_locked that controls access to a
// BankAccount
template <typename T, typename LockableT> class externally_locked {
    // This macro is used to check that a given template parameter meets
    // certain requirements of has certain properties
    BOOST_CONCEPT_ASSERT((boost::BasicLockable<LockableT>));

  public:
    externally_locked(T& obj, LockableT& lockable) : obj_(obj), lockable_(lockable) {}

    externally_locked(LockableT& lockable) : obj_(), lockable_(lockable) {}

    T& get(boost::strict_lock<LockableT>& lock) {
        if (!lock.owns_lock(&lockable_))
            throw boost::lock_error(); // run time check throw if not matching locks
        return obj_;
    }

    void set(T const& obj, LockableT& lockable) {
        obj_      = obj;
        lockable_ = lockable;
    }

  private:
    T          obj_;
    LockableT& lockable_;
};

class BankAccount {
    int balance_;

  public:
    void Deposit(int amount) { balance_ += amount; }
    void Withdraw(int amount) { balance_ -= amount; }
};

class AccountManager : public boost::basic_lockable_adapter<boost::mutex> {
  public:
    using lockable_base_type = basic_lockable_adapter<boost::mutex>;
    AccountManager() : checkingAcct_(*this), savingsAcct_(*this) {}
    inline void Checking2Savings(int amount);
    inline void AMoreComplicatedChecking2Savings(int amount);

  private:
    externally_locked<BankAccount, AccountManager> checkingAcct_;
    externally_locked<BankAccount, AccountManager> savingsAcct_;
};

void AccountManager::Checking2Savings(int amount) {
    boost::strict_lock<AccountManager> guard(*this);
    checkingAcct_.get(guard).Withdraw(amount);
    savingsAcct_.get(guard).Deposit(amount);
}

int main() {
    AccountManager mgr;

    mgr.Checking2Savings(999);
}

To also make AccountManager::AMoreComplicatedFunction work you need quite a bit more plumbing as explained in the tutorial