6

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<Alpha*> s;

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

ただし、私の実際のケースでは、Foo::r関数は非常に複雑であり、その実装を非表示にしたいと考えています。Foo特に、実装では、クラスの宣言時に含める必要のない追加のライブラリを使用します。

ただし、 の定義がFoo::r宣言から分離されている場合は、戻り値の型を明示的に指定する必要があります。decltypeいくつかの助けが付属しています

ヘッダー ファイル:

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

実装、cpp ファイル:

#include "Foo.h"

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

これにより、 の実際の実装を隠すという即時の仕事が行われFoo::rます。ただし、戻り値の型は、範囲がどのように構築されているかに関する情報を効果的に「漏らします」。さらに悪いことstd::functionに、範囲パイプラインでオブジェクトを明示的に使用する必要があります。

しかし、返された範囲のユーザーが本当に必要としている情報はそれだけでしょうか? すべてのユーザーがFoo::r気にかけているのは、それがある種の反復可能であることです。それは持っています:

  • begin()範囲の先頭に反復子を与える
  • end()イテレータまたは番兵を与える
  • イテレータをインクリメントして、範囲を反復することができます
  • イテレータは逆参照することができ、いくつかの型T(Beta*例の場合) を与えます。

ユーザーは、変換ビューの有無や、変換、フィルターなどの数を気にしません。

それで、私の質問は- そのすべての情報を隠す方法はありますか? 私はこのようなものを書くことができるようにしたいと思います:

ヘッダー内:

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

  Iterable<Beta*> r();
};

cpp ファイルで:

#include "Foo.h"

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

Iterable生成された型には、非表示プロセスのためにインライン化できない実際の関数呼び出しが含まれている可能性があるという事実を受け入れることができます。リンク時の最適化では、後で最適化できる場合とできない場合があります。

残念ながら、私の知る限り、Iterableこれは単なる概念であり、ライブラリ内の個別の型ではありません。

4

1 に答える 1