显式范围-v3十进制类型评估为无效?

时间:2018-12-07 06:16:39

标签: c++ c++17 range-v3

我正在尝试获取范围的显式类型(将来我可能希望将其存储为类中的字段)。但是,由于某种原因,它的值为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 15.9版中收到类似错误


这个问题是我其他问题的延续:How to store a range as a field in a class?,但更具体,我认为应该将其分开。

1 个答案:

答案 0 :(得分:4)

您的代码无效,原因是:

  • range / v3视图禁用右值视图,因为这将导致悬空引用。因此,在您的declval()中,您还应该使用左值:

    std::declval<std::set<Alpha*>&>()
    //                           ^ here should be lvalue
    
  • 视图转换信息被编码在template参数内。因此,如果使用view::transform(std::function<Beta*(Alpha*)>())表示类型,则表达式应具有完全相同的类型。 Lambda不好。

有效版本为:

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

但是实际上,以这种方式存储视图不是一个好主意。