【问题标题】:Explicit range-v3 decltype evaluates to void?显式 range-v3 decltype 评估为无效?
【发布时间】:2018-12-07 06:16:38
【问题描述】:

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


这个问题是我的另一个问题的延续:How to store a range as a field in a class?,但更具体,我相信它应该分开。

【问题讨论】:

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


    【解决方案1】:

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

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

      std::declval<std::set<Alpha*>&>()
      //                           ^ here should be lvalue
      
    • 视图转换信息在模板参数中进行编码。因此,如果您使用view::transform(std::function&lt;Beta*(Alpha*)&gt;()) 来表示类型,那么您的表达式应该具有完全相同的类型。 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); }
              });
    }
    

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

    【讨论】:

    • @CygnusX1 这可能是基于意见的。视图的类型是其用户不应该关心的实现细节。我不知道你为什么要存储那个类型,我会使用auto作为返回类型,让编译器去推断。
    • 具有讽刺意味的是,出于完全相同的原因,我需要该类型。函数体是一个实现细节,我想把它移到 cpp 文件中。但这使得声明站点的返回类型没有任何可扣除的内容,因此它不能是自动的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-02-01
    • 1970-01-01
    • 2020-06-03
    • 1970-01-01
    • 2022-08-10
    相关资源
    最近更新 更多