C++ 显式range-v3 decltype的计算结果为void?

C++ 显式range-v3 decltype的计算结果为void?,c++,c++17,range-v3,C++,C++17,Range V3,我试图获得一个范围的显式类型(将来可能希望将其存储为类中的字段)。但是,由于某种原因,它的计算结果为无效 #include <iostream> #include <set> #include <range/v3/view/transform.hpp> class Alpha { public: int x; }; class Beta : public Alpha { }; class Foo { public: std::set<Al

我试图获得一个范围的显式类型(将来可能希望将其存储为类中的字段)。但是,由于某种原因,它的计算结果为
无效

#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++版本g++(Ubuntu 7.3.0-27ubuntu1~18.04)7.3.0)

我在Visual Studio 2017上遇到了类似的错误,v。15.9



这个问题是我另一个问题的延续:但更为具体,我认为应该将其分开。

您的代码不起作用,因为:

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

    std::declval<std::set<Alpha*>&>()
    //                           ^ here should be lvalue
    
    std::declval()
    //^这里应该是左值
    
  • 视图转换信息编码在模板参数中。因此,如果使用
    view::transform(std::function())
    表示类型,则表达式的类型应该完全相同。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); }
          });
}
class-Foo{
公众:
std::集s;
使用RangeReturn=decltype(std::declval()| ranges::v3::view::transform(std::function());
测距仪();
};
Foo::RangeReturn Foo::r(){
返回s | ranges::v3::view::transform(std::function{
[](Alpha*a){返回静态_cast(a);}
});
}

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

@CygnusX1它可能是基于观点的。视图的类型是用户不应该关心的实现细节。我不知道您为什么要存储该类型,我会使用
auto
作为返回类型,让编译器进行推断。具有讽刺意味的是,我需要该类型的原因与此完全相同。函数体是一个实现细节,我想把它移到cpp文件中。但这使得声明站点的返回类型没有任何可扣除的内容,因此它不能是自动的。
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); }
          });
}