2

さまざまな形式のピクセルを操作するコンテナー クラスがあります。一部の形式はピクセルをメモリに格納するだけなので、コンテナーの参照型は Pixel& です。他の形式では、ピクセルがパックされたバイトで格納されます。参照を返すものがないため、その場合の参照型はプロキシ型です。すべてのプロキシ タイプには、基になるピクセルのタイプである value_type という組み込みの typedef があります。

ピクセルを操作するファンクターを作成しようとすると、問題が発生します。たとえば、次のようなものを書きたいと思います。

std::for_each( container.begin(), container.end(), Incrementer() );

これを2つの異なる方法で機能させることができましたが、どちらも好きではないので、これを改善できるかどうか疑問に思っています.

最初の方法は次のとおりです。

struct Incrementer {

  template <typename Pixel>
  void operator()( Pixel& p ) {
    p = p + 1;
  } 

  template <typename Proxy>
  void operator()( Proxy p, typename Proxy::value_type* dummy=0 ) {
    p = p + 1;
  }
};

基本的な考え方は、コンテナーがピクセルへの参照を返す場合とプロキシを返す場合の 2 つのオーバーロードがあるということです。参照ケースが明確になるように、2 番目のオーバーロードの仮引数が必要です。これの問題は、私が使用するすべてのファンクターがこれら 2 つのオーバーロード (仮引数を含む) を必要とすることです。

おそらく、引数の型を整理するためのテンプレート マジックを作成することもできますが、コンパイラが参照引数を推論しないという問題に直面し続けるため、非 const 参照を使用してオーバーロードを提供する必要があります。一方、プロキシは一時的なものであるため、非 const 参照で渡すことはできません。そのため、2 つのオーバーロードで立ち往生しています。

足りないものはありますか?

フォールバック ソリューションは次のようになります。

  template < typename PixelReference >
  struct Incrementer {

    void operator()( PixelReference p ) {
      p = p + 1;
    }
  };

  std::for_each( container.begin(), container.end(),      
                 Incrementer< pixel_traits<Pixel,Format>::reference >() );

(ピクセルの特性クラスがあると仮定します)。ここで、ファンクタを作成するときに参照型を指定する必要がありますが、これは面倒なことがよくあります。

これらの代替案のいずれかを改善する方法はありますか? 私はこのコンテナーをライブラリーとして作成しているので、ファンクターの作成と使用をできるだけ簡単にしようとしています。

ありがとう。

4

2 に答える 2

2

使用はあなたをstd::for_each()妨げているかもしれません。std::transform()代わりに使用するとどうなりますか?同じインプレース変更もサポートしています。

transform( container.begin(), container.end(), container.begin(), Incrementer() );

ピクセルをそのIncrementer::operator()場で明示的に変更しなくなるため、値渡しの場合にのみ実装する必要があります。もちろん、イテレータへのプロキシ値の割り当てをサポートする必要がありますが、おそらくそれほど難しくありません。

于 2013-06-03T13:59:45.543 に答える
0

あなたの問題を解決する方法はいくつかあると思います。

1.あなたの例では、両方operator()の s が同一であるため、すでにコンパイル時のポリモーフィズムを使用しており、問題は複数の定義ですoperator()

編集

コードは次のようになります。

struct Incrementer {
  template <typename Pixel_or_Proxy>
  void operator()( Pixel_or_Proxy& p ) {
    p = p + 1;
  }
};

2.boost enable_if と disable_ifを使用し、 boost.mpl BOOST_MPL_HAS_XXX_TRAIT_DEFを使用してチェックvalue_typeします。

3. プロキシがテンプレートの場合、より適切なオーバーロードを作成できます。

template<class T>
void operator()(T t) { 
  // normal operation
}

template<class T>
void operator()(Proxy<T> t) {
  // proxy operation
}

編集

オプション 2 へ: メソッドの本体は等しいので、1 つのテンプレート メソッドを記述するだけで済みます。型名PixelProxyは、コンパイラにとって意味的な意味を持たない単なる名前であり、ユーザーにとってのみです。コンパイラは、指定された型でテンプレート メソッドをインスタンス化するだけです。異なるメソッドがある場合は、オーバーロードによってそれらのいずれかを選択する必要があります。これは、enable_if とその仲間を使って、またはtype traits の助けを借りて追加の呼び出しを介して行うことができます。

于 2013-06-03T14:37:10.760 に答える