显式range-v3 decltype计算结果为void



我正在尝试获取一个范围的显式类型(将来我可能想将其存储为类中的字段(。然而,由于某种原因,它的评估结果为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 上遇到了类似的错误


这个问题是我另一个问题的延续:如何将范围存储为类中的字段?但更具体,我认为应该分开。

您的代码无法工作,因为:

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

    std::declval<std::set<Alpha*>&>()
    //                           ^ here should be lvalue
    
  • 视图转换信息被编码在模板参数内。因此,如果使用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); }
});
}

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

相关内容

最新更新