6

intr値またはl値(const)参照によって、パラメータ(具体的な型、たとえば )をメンバー関数に渡したいと考えています。私の解決策は次のとおりです。

#include <type_traits>
#include <utility>

struct F
{
    using desired_parameter_type = int;

    template< typename X, typename = typename std::enable_if< std::is_same< typename std::decay< X >::type, desired_parameter_type >::value >::type >
    void operator () (X && x) const
    {
        // or even static_assert(std::is_same< typename std::decay< X >::type, desired_parameter_type >::value, "");
        std::forward< X >(x); // something useful
    }
};

別の例はここhttp://pastebin.com/9kgHmsVCです。

しかし、それは冗長すぎます。より簡単な方法でそれを行う方法は?

の代わりにstd::remove_referenceとの重ね合わせを使用する必要があるかもしれませんが、ここでは単純化しています。std::remove_conststd::decay

4

3 に答える 3

4

私があなたの質問を正しく理解していれば、パラメーターが右辺値参照 (右辺値が提供されている場合) または左辺値参照const(左辺値が提供されている場合) のいずれかである単一の関数が必要です。

しかし、この関数は何をするのでしょうか? 左辺値が提供される場合を含め、両方のケースを処理できる必要があるため、入力を変更することはできません (少なくともパラメーターにバインドされたものは変更できません)。変更すると、参照xのセマンティクスに違反します。 const.

ただし、パラメーターの状態を変更できない場合は、右辺値参照を許可する理由はありません。むしろ、常にx左辺値参照にするconst必要があります。への左辺値参照は右辺値にconstバインドできるため、右辺値と左辺値の両方を渡すことができます。

渡されるものに基づいて関数のセマンティクスが異なる場合は、そのような関数を2 つ記述する方が理にかなっていると言いますconst

于 2013-05-04T16:51:57.217 に答える
1

Andy が述べたように、ここで重要なことは、関数内で実際に何ができるかということです

  • 引数を別の関数に転送できます。この場合、テンプレートの使用は問題ではありません。間違ったパラメーターの型が指定された場合でも、コンパイル エラー (間違った型が 2 番目の関数に送信される) が発生するためです。使用できますtemplate <typename T> blah (T && x)
  • それ以外の場合は、r 値参照か l 値参照かによって異なるコードを記述する必要があるため、とにかく 2 つの関数を記述する必要があります:blah (const int & x)blah (int && x).

最初のオプションを試しているに違いなく、潜在的なコンパイラエラーをよりユーザーフレンドリーにしようとしていると思います。まあ、それだけの価値はないと思います。プログラマーは、適切なコンパイラーの出力に「…によって呼び出された」リストを表示します。

于 2013-05-04T17:02:55.317 に答える
1

実際、これは非常に良い質問です。これまでのところ、ユニバーサル リファレンス トリックとenable_ifハンマーも使用してきました。ここでは、テンプレートを使用せず、代わりに左辺値キャストを使用するソリューションを紹介します。

ofstream以下は、 C++98 では不可能な (または非常に難しい) インプレース使用の既知の例を使用して状況が発生する実際の例です(ostringstreamより明確にするために例で使用しています)。

最初に、C++98 でよく見られる左辺値参照の関数が表示されます。

#include<iostream>
#include<sstream>
struct A{int impl_;};

std::ostringstream& operator<<(std::ostringstream& oss, A const& a){
    oss << "A(" << a.impl_ << ")"; // possibly much longer code.
    return oss;
}
// naive C++11 rvalue overload without using templates
std::ostringstream& operator<<(std::ostringstream&& oss, A const& a){
    oss << "A(" << a.impl_ << ")"; // ok, but there is code repetition.
    return oss;
}

int main() {

    A a{2};
    {// C++98 way
        std::ostringstream oss;
        oss << a;
        std::cout << oss.str() << std::endl; // prints "A(2)", ok"
    }
    {// possible with C++11, because of the rvalue overload
        std::cout << (std::ostringstream() << a).str() << std::endl; //prints "A(2)", ok
    }
}

C++11 でわかるように、C++98 ではできないことを実現できます。それは、ostringstream(またはofstream) インプレースを利用することです。ここで OP の質問が来ます。2 つのオーバーロードは非常に似ていますが、両方を 1 つに結合できますか?

1 つのオプションは、ユニバーサル参照 ( Ostream&&) を使用し、オプションでenable_if型を制約することです。あまりエレガントではありません。

この「実世界」の例を使用して私が見つけたのは、左辺値参照と右辺値参照に同じコードを使用したい場合、おそらく一方を他方に変換できるからです!

std::ostringstream& operator<<(std::ostringstream&& oss, A const& a){
    return operator<<(oss, a);
}

これは無限再帰関数のように見えますossが、左辺値参照のためではありません (そうです、名前があるため左辺値参照です)。したがって、他のオーバーロードが呼び出されます。

2 つの関数を作成する必要がありますが、1 つのコードは維持する必要がありません。

要約すると、(非 const) 左辺値参照と右辺値の両方に関数を適用することが「理にかなっている」場合、それは右辺値を左辺値に変換できるため、単一の関数に転送できることも意味します。「理にかなっています」は、コンテキストと意図したコードの意味に依存することに注意してください。これは、左辺値のオーバーロードを明示的に呼び出すことによってコンパイラに「伝える」必要があるものです。

これが普遍的な参照を使用するよりも優れていると言っているのではありません。それは代替手段であり、間違いなく意図はより明確です。

ここで編集可能なコード: http://ideone.com/XSxsvY . (フィードバックは大歓迎です)

于 2014-02-04T00:25:48.033 に答える