Possible bug with decltype and access modifer order

Please see this stackoverflow question for an overview. http://stackoverflow.com/questions/14188535/clang-access-modifier-order-and-decltype

The issue seems to be that the private members are not visible at compilation to the decltype call. This is a minimum example (from the question). (I am the questioner in this case). This also seems to appear as a ‘bug’ in gcc but not msvc (12). I am not 100% convinced but cannot find in the standard why this will not work. I hope this helps.


#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;
}

Best Regards
David Irvine

maidsafe.net Limited is a limited liability company incorporated in Scotland with number SC297540. VAT Registered 889 0608 77. Registered Office: 72 Templehill, Troon, KA10 6BE.
Telephone Scotland: +44 1292 750020.

The instantiation of the template looks like this:

template<> class Synchronisedstd::string : Dependentstd::string { public: explicit Synchronised(std::string t = std::string()) : t_(t) {} template auto operator()(Functor functor) const ->decltype(functor(self(*this).t_)) { std::lock_guardstd::mutex lock(mutex_); return functor(t_); } private: mutable std::string t_; mutable std::mutex mutex_; };

This is ill-formed, since t_ has not yet been declared when the trailing-return-type for operator() is processed. Per [basic.lookup.classref]p2, the name t_ is looked up in the scope of class Synchronizedstd::string. Per [basic.scope.class]p1, the name is not in scope in the trailing-return-type, because it is not in the declarative region following the name’s point of declaration, and isn’t a function body, default argument, nor non-static data member initializer.

Thanks very much for the answer

Does this then indicate that auto func()-> decltype(stuff private_member)
as a member function is always processed prior to the objects constructor
initialises data members (private_member in this case). ?

If this is the case or there any other times where private should come
before public accessors, if so and Chandler is listening then there is an
interesting change to the Google style guide :slight_smile:

Please see this stackoverflow question for an overview.
http://stackoverflow.com/questions/14188535/clang-access-modifier-order-and-decltype

The issue seems to be that the private members are not visible at
compilation to the decltype call. This is a minimum example (from the
question). (I am the questioner in this case). This also seems to appear as
a 'bug' in gcc but not msvc (12). I am not 100% convinced but cannot find in
the standard why this will not work. I hope this helps.

#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;
}

Best Regards
David Irvine

maidsafe.net Limited is a limited liability company incorporated in
Scotland with number SC297540. VAT Registered 889 0608 77. Registered
Office: 72 Templehill, Troon, KA10 6BE.
Telephone Scotland: +44 1292 750020.

_______________________________________________
cfe-dev mailing list
cfe-dev@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev

The instantiation of the template looks like this:

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

This is ill-formed, since t_ has not yet been declared when the
trailing-return-type for operator() is processed. Per
[basic.lookup.classref]p2, the name t_ is looked up in the scope of class
Synchronized<std::string>. Per [basic.scope.class]p1, the name is not in
scope in the trailing-return-type, because it is not in the declarative
region following the name's point of declaration, and isn't a function body,
default argument, nor non-static data member initializer.

Thanks very much for the answer

Does this then indicate that auto func()-> decltype(stuff private_member) as
a member function is always processed prior to the objects constructor
initialises data members (private_member in this case). ?

It means that it's parsed where it appears in the class body (or at
least, it's allowed to be parsed then, see [basic.scope.class]p1 for
the details). The constructor is not relevant, but the location of the
declaration of the class member (relative to its use) is.

If this is the case or there any other times where private should come
before public accessors, if so and Chandler is listening then there is an
interesting change to the Google style guide :slight_smile:

Well, the Google style guide does not allow trailing return types, nor
decltype...