Порядок модификатора доступа Clang и тип decltype

Я пытался создать класс шаблона помощника синхронизатора, основанный на идеях Херба Саттера о классе-оболочке в этом говорить Это не работает в msvc как есть (если мы не удалим инициализацию фигурной скобки), но когда инициализация фигурной скобки удалена, тогда это нормально.

В clang / gcc (ubuntu 12.10, gcc4.7.2, clang (3.2), собранный с помощью libc ++) кажется, что модификатор приватного доступа должен появляться перед публикой: что кажется немного странным.

Ошибка в gcc есть
error: ‘t_’ was not declared in this scope

и лязг

error: use of undeclared identifier 't_'
auto operator()(F f) const ->decltype(f(t_))

Это может быть проблема шаблона / declytpe, о которой я не знаю, и мне интересно, может ли кто-нибудь помочь с этим. (все скомпилировано с соответствующими флагами c ++ 11)

template <class T>
class Synchronised {
public:
Synchronised(T t = T{}) : t_{t} {}
template <typename F>
auto operator()(F f) const -> decltype(f(t_)) {
std::lock_guard<std::mutex> lock{mutex_};
return f(t_);
}
private: // place this before public: and this object compiles
mutable T t_;
mutable std::mutex mutex_;
};

Редактировать: Добавление идей Йоханнеса и полный класс на случай, если кто-то хочет вырезать и вставить.

#include <future>
#include <iostream>
#include <thread>
#include <vector>

template <class T> T &self(T &t) { return t;  }
template<typename T> struct Dependent {  };

template<typename T>
class Synchronised : Dependent<T>{
public:
explicit Synchronised(T t = T()) : t_(t) {}
template<typename Functor>
auto operator()(Functor functor) const ->decltype(functor(self(*this).t_)) {
//auto operator()(Functor functor) const ->decltype(functor(this->t_)) {
std::lock_guard<std::mutex> lock(mutex_);
return functor(t_);
}
private:
mutable T t_;
mutable std::mutex mutex_;
};int main() {

Synchronised<std::string> sync_string("Start\n");
std::vector<std::future<void>> futures;
}

4

Решение

Приведенного ниже было достаточно только для того, чтобы сделать само определение шаблона класса действительным. Однако те же правила, которые заставили поиск не находить член данных в шаблоне класса (что требовало введения пустого зависимого базового класса или вызова зависимой функции), также приведут к тому, что экземпляр шаблона класса не найдет член данных, и тем самым вызовет ошибку компилятора.

Мы сказали компилятору: «Держись, возможно, ты найдешь элемент данных во время создания экземпляра», но я не думал о том, что произойдет при создании экземпляра. Теперь мы сделаем так, чтобы имя все еще зависело даже после того, как произошло создание экземпляра класса. Решение придется ждать до звонка operator(),

// keep this little util somewhere :)
template<typename T>
struct self {
template<typename U> U &operator()(U &t) { return t; }
};

template <class T>
class Synchronised {
public:
// ...
auto operator()(F f) const -> decltype(f(self<F>()(*this).t_)) {
// ...
};

Использование шаблона класса для self вместо шаблона функции также предотвратит поиск, зависящий от аргумента, что не позволит автору F также пишет функцию под названием self это соответствует аргументу *this (это могло быть потенциальной проблемой с частичным решением ниже).


У вас есть несколько других вариантов, кроме переупорядочения

  1. Делая выражение на левой стороне . зависимый, но не только включающий класс (потому что это будет специальный случай)

    // keep this little util somewhere :)
    template <class T> T &self(T &t) { return t; }
    
    template <class T>
    class Synchronised {
    public:
    // ...
    auto operator()(F f) const -> decltype(f(self(*this).t_)) {
    // ...
    };
    
  2. Введение зависимого базового класса для обхода специального корпуса включающего класса

    // Keep this little util somewhere
    template<typename T> struct Dependent { };
    
    template <class T>
    class Synchronised : Dependent<T> {
    public:
    // ...
    auto operator()(F f) const -> decltype(f(this->t_)) {
    // ...
    };
    

Первый основан на создании стандарта self(*this).t_ член неизвестной специализации

  • тип выражения объекта является зависимым и не является текущей реализацией.

Второй основан на создании стандарта this->t_ член неизвестной специализации

  • типом выражения объекта является текущий экземпляр, текущий экземпляр имеет по меньшей мере один зависимый базовый класс, и поиск имени для id-выражения не находит члена текущего экземпляра или его независимого базового класса;

Это в свою очередь делает x->t_ для обоих случаев зависимое выражение и, следовательно, имя будут найдены во время создания экземпляра. Стандарт говорит

Выражение доступа к члену класса (5.2.5) зависит от типа, если выражение относится к члену текущего экземпляра и тип ссылочного члена является зависимым, или выражение доступа к члену класса относится к члену неизвестной специализации.

4

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector