10

次のコードがあります。例として、dec_proxyは、複雑な関数呼び出しfooで実行される型に対するインクリメント演算子の効果を逆転させようとします。これは、インターフェイスを変更できません。

#include <iostream>

template<typename T>
class dec_proxy
{
public:
   dec_proxy(T& t)
   :t_(t)
   {}

   dec_proxy<T>& operator++()
   {
      --t_;
      return *this;
   }

private:
   T& t_;
};

template<typename T, typename S, typename R>
void foo(T& t, S& s, R& r)
{
  ++t;
  ++s;
  ++r;
}

int main()
{
   int i = 0;
   double j = 0;
   short  k = 0;

   dec_proxy<int> dp1(i);
   dec_proxy<double> dp2(j);
   dec_proxy<short> dp3(k);

   foo(dp1,dp2,dp3);

   //foo(dec_proxy<int>(i),     <---- Gives an error
   //   dec_proxy<double>(j),     <---- Gives an error
   //   dec_proxy<short>(k));      <---- Gives an error 

   std::cout << "i=" << i << std::endl;

   return 0;
}

問題は、dec_proxyを使用したいさまざまなタイプについて、現在dec_proxyの特殊なインスタンスを作成する必要があることです。これは非常に厄介で制限されたアプローチのようです。

私の質問は次のとおりです。非定数参照パラメーターなどの短期間の一時的なものを渡す正しい方法は何ですか?

4

3 に答える 3

14

スティーブンのアドバイスを受けて、なぜ非定数参照が一時オブジェクトにバインドできないのかという答えを見る必要があります。参照を返すメンバー関数を追加するだけですdec_proxy。例:

dec_proxy &ref() { return *this; }

と電話foo

foo(
    dec_proxy<int>(i).ref(), 
    dec_proxy<double>(j).ref(), 
    dec_proxy<short>(k).ref());

私はそれがコンパイルされるとかなり確信しています。

于 2011-10-05T07:15:12.657 に答える
7

MSNのおかげで、ソリューションは次のようになります。

関数テンプレートを追加しても正しくないと思いますtemplate<typename T> dec_proxy_impl<T>& dec_proxy(T&t)

それがしたのは、コンパイラをだましているだけです。ランタイムエラーが発生します。この関数fooには、lvaueまたはlvalue参照が必要です。ただしtemplate<typename T> dec_proxy_impl<T>& dec_proxy(T&t)、有効な左辺値参照を返しません。実装では、一時オブジェクトを作成して返します。関数呼び出しが終了すると、一時オブジェクトは破棄されます。したがって、関数に渡された値の参照fooは間違っています。実際、参照されているオブジェクトはすでに破棄されています。は++t;++s;++r無効なオブジェクトにアクセスしようとしています。動作は未定義です。

MSNからの解決策は正しいです。オブジェクトの存続期間はdec_proxy<int>(i)、その宣言から関数呼び出しの終了までです。関数fooのパラメーターが有効であることを確認します。

于 2011-10-05T08:33:58.830 に答える
2

あなたがやろうとしていることは、左辺値(your new dec_facade<int>(i))を左辺値参照として渡すことです。これは、それが機能しない理由を説明しています。

コンパイラがサポートしている場合は、&&型修飾子を使用して右辺値参照を使用できます:(右辺値参照のサポートは、C++0xまたはC++11 [部分]サポートをオンにすることで有効にできます)

template<typename T>
void foo(T& t)
{    
    ++t;
}
template<typename T>
void foo(T&& t)
{    
    ++t;
}

しかし、それは問題のほんの一部です。あなたがやろうとしていることは、一時的な値を事前にインクリメントすることです!それはその呼び出しの後に生きていないので、それは意味がありません。オブジェクトは増分されてから破棄されます。


もう1つの解決策は、関数定義からを削除することです。これにより、任意のパラメーター&を受け入れることができます。しかし、それはおそらくあなたが望むものではありません。

于 2011-10-05T07:03:25.497 に答える