135

参照によってパラメーターを渡すときに、関数のパラメーターにデフォルト値を与えることは可能ですか?C++で

たとえば、次のような関数を宣言しようとすると、次のようになります。

virtual const ULONG Write(ULONG &State = 0, bool sequence = true);

これを行うと、エラーが発生します。

エラーC2440:'デフォルトの引数':'constint'から'unsigned long&'に変換できません'const'以外の参照は非左辺値にバインドできません

4

17 に答える 17

120

const参照に対しては実行できますが、非const参照に対しては実行できません。これは、C ++では一時(この場合はデフォルト値)を非定数参照にバインドできないためです。

これを回避する1つの方法は、実際のインスタンスをデフォルトとして使用することです。

static int AVAL = 1;

void f( int & x = AVAL ) {
   // stuff
} 

int main() {
     f();       // equivalent to f(AVAL);
}

しかし、これは非常に限られた実用的な用途です。

于 2009-06-29T18:08:41.203 に答える
39

あなたの回答への直接のコメントの1つですでに言われていますが、公式に述べるだけです。あなたが使いたいのはオーバーロードです:

virtual const ULONG Write(ULONG &State, bool sequence);
inline const ULONG Write()
{
  ULONG state;
  bool sequence = true;
  Write (state, sequence);
}

関数のオーバーロードを使用すると、追加の利点もあります。まず、任意の引数をデフォルトにすることができます:

class A {}; 
class B {}; 
class C {};

void foo (A const &, B const &, C const &);
void foo (B const &, C const &); // A defaulted
void foo (A const &, C const &); // B defaulted
void foo (C const &); // A & B defaulted etc...

派生クラスの仮想関数にデフォルトの引数を再定義することもできます。これは、オーバーロードによって回避されます。

class Base {
public:
  virtual void f1 (int i = 0);  // default '0'

  virtual void f2 (int);
  inline void f2 () {
    f2(0);                      // equivalent to default of '0'
  }
};

class Derived : public Base{
public:
  virtual void f1 (int i = 10);  // default '10'

  using Base::f2;
  virtual void f2 (int);
};

void bar ()
{
  Derived d;
  Base & b (d);
  d.f1 ();   // '10' used
  b.f1 ();   // '0' used

  d.f2 ();   // f1(int) called with '0' 
  b.f2 ();   // f1(int) called with '0
}

デフォルトを実際に使用する必要がある状況は 1 つだけで、それはコンストラクター上です。あるコンストラクターを別のコンストラクターから呼び出すことはできないため、この手法はその場合には機能しません。

于 2009-06-29T18:59:02.800 に答える
29

オプションの引数を提供する古い C の方法がまだあります。存在しない場合は NULL になる可能性のあるポインターです。

void write( int *optional = 0 ) {
    if (optional) *optional = 5;
}
于 2010-01-19T15:30:04.560 に答える
11

この小さなテンプレートは次のことに役立ちます。

template<typename T> class ByRef {
public:
    ByRef() {
    }

    ByRef(const T value) : mValue(value) {
    }

    operator T&() const {
        return((T&)mValue);
    }

private:
    T mValue;
};

次に、次のことができるようになります。

virtual const ULONG Write(ULONG &State = ByRef<ULONG>(0), bool sequence = true);
于 2011-10-29T03:50:05.823 に答える
8

引数を参照で渡す理由は 2 つあります。(1) パフォーマンスのため (この場合は const 参照で渡したい)、(2) 関数内で引数の値を変更する機能が必要なためです。

最新のアーキテクチャで unsigned long を渡すと、速度が大幅に低下することはないと思います。Stateしたがって、メソッド内の値を変更するつもりであると想定しています。0定数は右辺値 (エラー メッセージの「非左辺値」) であり、変更不可 (エラー メッセージの) であるため、定数を変更できないため、コンパイラは不平を言っていconstます。

簡単に言えば、渡された引数を変更できるメソッドが必要ですが、デフォルトでは、変更できない引数を渡したいとします。

別の言い方をすれば、非const参照は実際の変数を参照する必要があります。関数シグネチャのデフォルト値 ( 0) は実変数ではありません。次と同じ問題が発生しています。

struct Foo {
    virtual ULONG Write(ULONG& State, bool sequence = true);
};

Foo f;
ULONG s = 5;
f.Write(s); // perfectly OK, because s is a real variable
f.Write(0); // compiler error, 0 is not a real variable
            // if the value of 0 were changed in the function,
            // I would have no way to refer to the new value

メソッド内で実際に変更するつもりがない場合はState、単純にconst ULONG&. しかし、それによってパフォーマンスが大幅に向上するわけではないため、非参照に変更することをお勧めしますULONG。あなたがすでに を返していることに気付きました。ULONG私は、その値がState必要な変更を加えた後の の値であるという卑劣な疑いを持っています。その場合、メソッドを次のように宣言するだけです。

// returns value of State
virtual ULONG Write(ULONG State = 0, bool sequence = true);

もちろん、あなたが何をどこに書いているのかよくわかりません。しかし、それはまた別の質問です。

于 2009-06-29T21:50:03.797 に答える
7

いいえ、できません。

参照渡しは、関数がパラメーターの値を変更する可能性があることを意味します。パラメータが呼び出し元によって提供されておらず、デフォルトの定数からのものである場合、関数は何を変更することになっていますか?

于 2009-06-29T18:10:13.650 に答える
6

関数呼び出しのパラメーターとして定数リテラルを使用できないのと同じ理由で、既定のパラメーターに定数リテラルを使用することはできません。参照値にはアドレスが必要ですが、定数参照値は必要ありません (つまり、r 値または定数リテラルにすることができます)。

int* foo (int& i )
{
   return &i;
}

foo(0); // compiler error.

const int* bar ( const int& i )
{
   return &i;
}

bar(0); // ok.

デフォルト値にアドレスがあることを確認してください。問題ありません。

int null_object = 0;

int Write(int &state = null_object, bool sequence = true)
{
   if( &state == &null_object )
   {
      // called with default paramter
      return sequence? 1: rand();
   }
   else
   {
      // called with user parameter
      state += sequence? 1: rand();
      return state;
   }
}

変数または null の可能性のあるパラメーターがある場合に、このパターンを数回使用しました。通常のアプローチは、ユーザーにポインターを渡すことです。値を入力してほしくない場合は、NULL ポインターを渡します。オブジェクトアプローチを無効にするのが好きです。呼び出し先のコードをひどく複雑にすることなく、呼び出し元の生活を楽にします。

于 2009-06-29T21:03:35.437 に答える
1

そうではないと思います。その理由は、デフォルト値は定数に評価され、定数参照として宣言しない限り、参照によって渡される値は変更できる必要があるためです。

于 2009-06-29T18:09:15.943 に答える
1

State の const 修飾子で可能です。

virtual const ULONG Write(const ULONG &State = 0, bool sequence = true);
于 2014-12-13T01:11:42.807 に答える
1

オブジェクト指向の場合...指定されたクラスが「デフォルト」を持っていると言うには、このデフォルト(値)を宣言する必要があり、デフォルトパラメータとして使用できることを意味します。例:

class Pagination {
public:
    int currentPage;
    //...
    Pagination() {
        currentPage = 1;
        //...
    }
    // your Default Pagination
    static Pagination& Default() {
        static Pagination pag;
        return pag;
    }
};

あなたの方法で...

 shared_ptr<vector<Auditoria> > 
 findByFilter(Auditoria& audit, Pagination& pagination = Pagination::Default() ) {

この場合、「グローバルデフォルトページネーション」は単一の「参照」値であるため、このソリューションは非常に適しています。また、「グローバルレベル」の構成のように、実行時にデフォルト値を変更することもできます。例: ユーザーのページネーションのナビゲーション設定など..

于 2014-05-14T14:25:27.247 に答える
1
void f(const double& v = *(double*) NULL)
{
  if (&v == NULL)
    cout << "default" << endl;
  else
    cout << "other " << v << endl;
}
于 2013-10-18T16:11:42.467 に答える
0
void revealSelection(const ScrollAlignment& = ScrollAlignment::alignCenterIfNeeded, bool revealExtent = false);
于 2011-04-27T12:58:00.793 に答える
0

これにはかなり汚いトリックもあります:

virtual const ULONG Write(ULONG &&State = 0, bool sequence = true);

この場合、次のように呼び出す必要がありますstd::move

ULONG val = 0;
Write(std::move(val));

これは面白い回避策にすぎません。実際のコードで使用することはお勧めしません。

于 2016-10-12T22:42:57.803 に答える
-3

virtual const ULONG Write(ULONG &State = 0, bool sequence = true);

答えは非常に単純で、私は説明が得意ではありませんが、この関数でおそらく変更される非 const パラメータにデフォルト値を渡したい場合は、次のように使用します。

virtual const ULONG Write(ULONG &State = *(ULONG*)0, bool sequence =
> true);
于 2012-06-14T13:41:34.167 に答える