Явный диапазон-v3 decltype оценивается как недействительный? - PullRequest
0 голосов
/ 07 декабря 2018

Я пытаюсь получить явный тип диапазона (возможно, я захочу сохранить его как поле в классе в будущем).Однако по какой-то причине он оценивается как void?

#include <iostream>
#include <set>
#include <range/v3/view/transform.hpp>

class Alpha {
public:
  int x;
};

class Beta : public Alpha {

};

class Foo {
public:
  std::set<Alpha*> s;

  using RangeReturn = decltype(std::declval<std::set<Alpha*>>() | ranges::v3::view::transform(std::function<Beta*(Alpha*)>()));
  RangeReturn r();
};

Foo::RangeReturn Foo::r() {
  return s | ranges::v3::view::transform([](Alpha* a) { return static_cast<Beta*>(a); });
}

int main() {
}

При компиляции с g ++ -std = c ++ 17 он дает

main.cpp:24:88: error: return-statement with a value, in function returning 'void' [-fpermissive]

(g ++ версия g ++ (Ubuntu 7.3.0-27ubuntu1 ~ 18.04) 7.3.0)

Я получаю ошибку подобного типа в Visual Studio 2017, v. 15.9


Этот вопрос является продолжением моегоДругой вопрос: Как сохранить диапазон как поле в классе? , но он более конкретен, и я считаю, что он заслуживает отдельного разделения.

1 Ответ

0 голосов
/ 07 декабря 2018

Ваш код не работает, потому что:

  • представление range / v3 отключает представление из rvalue, потому что это приведет к зависанию ссылки.Таким образом, в вашем declval() вы также должны использовать lvalue:

    std::declval<std::set<Alpha*>&>()
    //                           ^ here should be lvalue
    
  • информация о преобразовании представления закодирована внутри параметра шаблона.Поэтому, если вы используете view::transform(std::function<Beta*(Alpha*)>()) для представления типа, ваше выражение должно иметь точно такой же тип.Лямбда не в порядке.

Рабочая версия будет выглядеть следующим образом:

class Foo {
public:
  std::set<Alpha*> s;

  using RangeReturn = decltype(std::declval<std::set<Alpha*>&>() | ranges::v3::view::transform(std::function<Beta*(Alpha*)>()));
  RangeReturn r();
};

Foo::RangeReturn Foo::r() {
  return s | ranges::v3::view::transform(std::function<Beta*(Alpha*)>{
          [](Alpha* a) { return static_cast<Beta*>(a); }
          });
}

Но на самом деле, это не очень хорошая идея для сохранения вида таким образом.

...