Скажем, мы пишем какой-то новый класс, который может использоваться одновременно или нет. Очевидно, что мы не хотим блокировать все на случай, если они будут вызваны одновременно. Одним из способов решения этой проблемы является параметризация с помощью Примеси указание блокировки:
template<class Locking>
struct foo : private Locking {
void bar() {
Locking::read_lock();
// Do something.
Locking::read_unlock();
}
};
и создание экземпляров Locking
с классом, который фактически блокируется для случая многопоточности, и с классом, который не выполняет никаких операций в другом случае (надеюсь, компилятор даже оптимизирует вызовы).
Теперь предположим, что я хотел бы сделать это с программно-транзакционной памятью вместо блокировки. Смотря на N3919 (или GCC предшественник), идея другая. Там нет звонков, таких как
transaction_start();
transaction_end();
Вместо этого есть спецификаторы функций, такие как
void bar() transaction_safe;
и блок спецификаторов, как
transaction { /* body */ }
со строгими правилами последнего вызова первого, и ничто из того, что выглядит так, не может быть использовано миксинами.
Как это может быть сделано(без с участием препроцессора)? Обратите внимание, что Одним из основных преимуществ СТМ является компоновка, но, кажется, нет способа заставить экземпляр отразить это bar
является предметом сделки.
Аналогично, с лямбдой кажется, что вы можете сделать что-то вроде:
template<class Transaction>
struct foo {
void bar() {
Transaction::run([](){ /* Do something. */ });
}
};
с 2 реализациями
template<typename F>
void TransactionNone::run(F f) { f(); }
а также
template<typename F>
void TransactionReal::run(F f) { transaction{ f(); } }
Для атрибутов
Функция безопасна для транзакций, если она не безопасна для транзакций.
Таким образом, вы можете опустить это ключевое слово и позволить компилятору / компоновщику выполнить эту работу.
Других решений пока нет …