2016-03-17 22 views
14

は私のコードです:メンバ関数呼び出しをデフォルト引数として使用できますか?ここ

struct S 
{ 
    int f() { return 1; } 
    int g(int arg = f()) { return arg; } 
}; 

int main() 
{ 
    S s; 
    return s.g(); 
} 

これはエラーでコンパイルに失敗します。thisは、そのコンテキストで使用することはできませんよう

error: cannot call member function 'int S::f()' without object 

this->f()をしようとすると、いずれかの動作しません。

デフォルトの引数を使用して、この作業を行う方法はありますか?もちろん


それがすべてでデフォルト引数を使用しないことで回避することができます。

int g(int arg) { return arg; } 
int g() { return g(f()); } 

は、しかし、冗長「実際のコード」によりarg前のパラメータ、およびいくつかがあることを考慮されることをこのパターンに従った関数。 (また、1つの関数に複数のデフォルト引数があった場合はさらに醜い)。

NB。 This questionは最初はよく似ていますが、実際に彼は別の問題であるクロージャをどのように形成するかを尋ねています(リンクされた解決策は私の状況には当てはまりません)。

+0

これは 'int g(){return g(f());にする必要があります。 } '、そうですか?少なくとも、実際のコードでは、それは多分意味をなさないでしょう。もちろん、ここでは 'g'の' return'文だけを持っています。 – skypjack

+0

@skypjackありがとう、固定 –

答えて

12

メンバーはstaticの場合にのみ使用できます。 C++ 11ドラフト(n3299)、§8.3.6/ 9:

Similarly, a non-static member shall not be used in a default argument, even if it is not evaluated, unless it appears as the id-expression of a class member access expression (5.2.5) or unless it is used to form a pointer to member (5.3.1).

これは動作します:これも(私は最初の式が何を意味するかだと思う)作品

struct S { 
    static int f() { return 1; } 
    int g(int arg = f()) { return arg; } 
}; 

int main() 
{ 
    S s; 
    return s.g(); 
} 

thisについては
struct S { 
    int f() { return 42; } 
    int g(int arg); 
}; 

static S global; 

int S::g(int arg = global.f()) { return arg; } 

int main() 
{ 
    S s; 
    return s.g(); 
} 

、それは確かに(§8.3.6/ 8)許可されていません。

The keyword this shall not be used in a default argument of a member function.

cppreference.comのdefault argumentsページには、サブジェットに関する詳細がたくさんあります。かなり複雑になります。

+1

また、キーワード「this」は、メンバ関数のデフォルト引数では使用しません。 – Jaege

+0

ありがとう@Jaege、その引用符を付け加えました。 – Mat

5

C++ 17の実験的な機能を使用することが許可されている場合は、STLのstd::optionalを使用できます(詳細はhereを参照)。他の点では

のようなもの:

int g(std::optional<int> oarg = std::optional<int>{}) { 
    int arg = oarg ? *oarg : f(); 
    // go further 
} 

EDIT

コメントで示唆したように、上記のコードは以下のいずれかに論理的に等価でなければなりません:

int g(std::optional<int> oarg = std::optional<int>{}) { 
    int arg = oarg.value_or(f()); 
    // go further 
} 

この1つは少し読みやすく(それはありませんか?)、いずれにしてもfを実行することに注意してください。
その機能が高価な場合は、多分それは価値がありません。

+0

実際のコードでは、引数は値ではなくconst参照によって取得されます。私はこれが最初に違いを生み出すとは思わなかった。私はあなたの解決策がまだ適用されると思う(wrapped型を 'reference_wrapper'か何かに変更できる) –

+0

@ M.Mええ、それでも適用されます。とにかく、私はもっと良い解決策を提供する別の答えを追加しました(少なくとも、開始点)。それがあなたに適したアプローチであるかどうか教えてください。 – skypjack

+0

ほんの少しの提案 - このような場合に '?:'の代わりに 'value_or'を使うべきだと思います。 – Predelnik

3

別の回答を追加します。これは以前の回答とはまったく異なり、問題を解決する可能性があります。
考え方は、別のクラスと、明示的および非明示的なコンストラクタの適切な組み合わせを使用することです。
最小限の作業例を次に示します。

#include <functional> 
#include <iostream> 

template<class C, int(C::*M)()> 
struct Arg { 
    std::function<int(C*)> fn; 
    Arg(int i): fn{[i](C*){ return i; }} { } 
    explicit Arg(): fn{[](C* c){ return (c->*M)(); }} { } 
}; 

struct S { 
    int f() { return 1; } 
    int h() { return 2; } 
    void g(int arg0, 
      Arg<S, &S::f> arg1 = Arg<S, &S::f>{}, 
      Arg<S, &S::h> arg2 = Arg<S, &S::h>{}) 
    { 
     std::cout << "arguments" << std::endl; 
     std::cout << "arg0: " << arg0 << std::endl; 
     std::cout << "arg1: " << arg1.fn(this) << std::endl; 
     std::cout << "arg2: " << arg2.fn(this) << std::endl; 
    } 
}; 

int main() { 
    S s{}; 
    s.g(42, 41, 40); 
    s.g(0); 
} 

の例では、デフォルトのパラメータと非不履行のものの両方を混在させることができる方法を示しています。
元の質問のように、それを修正して空の引数リストを持つ関数にすることは非常に簡単です。g
私は、例を洗練して、それよりも優れたもので終わることができると確信しています。とにかく、始めるのが良いポイントになるはずです。それは解決策が質問から元の例に適用される次の

#include <functional> 

template<class C, int(C::*M)()> 
struct Arg { 
    std::function<int(C*)> fn; 
    Arg(int i): fn{[i](C*){ return i; }} { } 
    explicit Arg(): fn{[](C* c){ return (c->*M)(); }} { } 
}; 

struct S { 
    int f() { return 1; } 
    int g(Arg<S, &S::f> arg = Arg<S, &S::f>{}) { 
     return arg.fn(this); 
    } 
}; 

int main() { 
    S s{}; 
    return s.g(); 
} 

そして、それがすべてです、それもstaticメソッドやグローバル変数なしで、それを行うことが可能です。
もちろん、我々はこの何とか使用することができます。言語を少し曲げることの問題です...

関連する問題