Используя это и атрибуты в конечных типах возвращаемых функций-членов? - PullRequest
6 голосов
/ 26 января 2012

В этом ответе , который я дал, имело смысл использовать this и атрибут класса _arg в конце типа возврата как часть выражения decltype. Можно обойтись без, но неудобно.

Ни clang 3.0 (см. Ниже), ни gcc 4.5.2 не приняли его.

#include <iostream>

class MyClass {
public:
  MyClass(int i): _arg(i) {}

  template <typename F>
  auto apply(F& f) -> decltype(f(_arg)) {
    return f(_arg);
  }

  template <typename F>
  auto apply(F& f) -> decltype(f(*this, _arg)) {
    return f(*this, _arg);
  }

private:
  int _arg;
};

struct Id {
  template <typename V>
  V operator()(V v) const { return v; }
};

struct ComplexId {
  template <typename C, typename V>
  V operator()(C const&, V v) { return v + 1; }
};

int main() {
  Id id; ComplexId complex;

  MyClass c(0);

  std::cout << c.apply(id) << " " << c.apply(complex) << "\n";
}

Clang 3.0 говорит:

$ clang++ -std=c++11 -Weverything test.cpp
test.cpp:8:38: error: use of undeclared identifier '_arg'
      auto apply(F& f) -> decltype(f(_arg)) {
                                     ^
test.cpp:8:45: error: type name requires a specifier or qualifier
      auto apply(F& f) -> decltype(f(_arg)) {
                                            ^
test.cpp:8:45: error: C++ requires a type specifier for all declarations
      auto apply(F& f) -> decltype(f(_arg)) {
                          ~~~~~~~~          ^
test.cpp:8:7: error: 'auto' return without trailing return type
      auto apply(F& f) -> decltype(f(_arg)) {
      ^
test.cpp:13:39: error: invalid use of 'this' outside of a nonstatic member function
      auto apply(F& f) -> decltype(f(*this, _arg)) {
                                      ^
test.cpp:13:52: error: type name requires a specifier or qualifier
      auto apply(F& f) -> decltype(f(*this, _arg)) {
                                                   ^
test.cpp:13:52: error: C++ requires a type specifier for all declarations
      auto apply(F& f) -> decltype(f(*this, _arg)) {
                          ~~~~~~~~                 ^
test.cpp:13:7: error: 'auto' return without trailing return type
      auto apply(F& f) -> decltype(f(*this, _arg)) {
      ^
8 errors generated.

Хм ... не так здорово.

Однако поддержка C ++ 11 в лучшем случае хакерская в большинстве компиляторов, и я не смог найти конкретных ограничений, упомянутых в Стандарте (n3290).

В комментариях Xeo предположил, что это могло быть дефектом в Стандарте ...

Итак, это разрешено или нет?

Бонус: а более поздние версии clang / gcc поддерживают это?

Ответы [ 3 ]

9 голосов
/ 26 января 2012

Я ошибаюсь.Это был дефект в какой-то момент , но в итоге был решен и утвержден в FDIS .

§5.1.1 [expr.prim.general]

Еслиобъявление объявляет функцию-член или шаблон функции-члена класса X, выражение this является значением типа «указатель на cv-qualifier-seq X» между необязательными cv-qualifer-seq и конец определения функции , декларатор-член или декларатор .

Таким образом, Clang и GCC просто пока не реализовали это правильно.

struct X{
  // 'this' exists between the | markers
  void f() const volatile | {
  } |
  auto g() const volatile | -> void {
  } |
};
5 голосов
/ 27 января 2012

Ваш код является недопустимым C ++ 11, поскольку класс не считается завершенным в типе возврата функции-члена. Вы можете получить доступ только к тем членам, которые были ранее объявлены. Вот так

class MyClass {
private:
  int _arg;

public:
  MyClass(int i): _arg(i) {}

  template <typename F>
  auto apply(F& f) -> decltype(f(_arg)) {
    return f(_arg);
  }

  template <typename F>
  auto apply(F& f) -> decltype(f(*this, _arg)) {
    return f(*this, _arg);
  }
};

По модулю да, использование this действительно в C ++ 11 в конце типа возврата.

1 голос
/ 26 января 2012

Я не знаю, законно ли то, что вы пишете, но есть и другие способы достичь того, чего вы хотите:

  template <typename F>
  auto apply(F& f) -> decltype(f(*(MyClass*)0, (int)0)) {
    return f(*this, _arg);
  }

Или:

  template <typename F>
  typename std::result_of<F(MyClass,int)>::type apply(F& f) {
    return f(*this, _arg);
  }
...