13

C++03 では、関数パラメーターをconstvolatile、左辺値参照 ( &) として修飾できます。

C++11 では、右辺値参照 ( ) がもう 1 つ追加されます&&

さらに、C++ では、パラメーターの修飾子に基づいて関数をオーバーロードできるため、関数を呼び出すときに最も適切なオーバーロードが選択されます。

メンバー関数は、概念的には、追加のパラメーターを受け取る関数と考えることができます。その型は、それがメンバーであるクラスのインスタンスへの参照です。この「追加パラメーター」の修飾子に基づいて、他のパラメーターとほぼ同じ方法でメンバー関数をオーバーロードすることができます。これは、修飾子を関数シグネチャの最後に置くことで表現されます。

struct Foo
{
    int& data();             // return a non-const reference if `this` is non-const
    const int& data() const; // return a const reference if `this` is const
};

C++03 ではconstandvolatile修飾子が可能であり、C++11 では&and &&(&理論的には C++03 で許可されていた可能性がありますが、そうではありませんでした) も許可されます。

C++03 では 2^2 = 4 の可能性があり、C++11 では 2^4-4 = 12 の可能性があるため、&とが相互に排他的であることを除いて、修飾子の任意の組み合わせを使用できます。&&

メンバー関数ポインターを操作したい場合、これは非常に面倒です。なぜなら、これらの修飾子は少しもポリモーフィックではないためです。this引数として渡されるメンバー関数ポインターの「型」の修飾子は、それらと正確に一致する必要があります。渡されるパラメーターのタイプ。C++ には、修飾子を抽象化するための明示的な機能もありません。constC++03 では、バージョンと非constバージョンを記述する必要があり、誰も気にしないため、これはほとんど問題ありませんでしvolatileたが、C++11 の病理学的ケース (病理学的ほど珍しいことではありません) 12 個ものオーバーロードを手動で作成する必要がある場合があります。機能ごと。

囲んでいるクラスの型をテンプレート パラメーターとして渡し、そこからメンバー関数ポインターの型を派生させると、修飾子constvolatile修飾子が許可され、期待どおりに伝播されることがわかり、とてもうれしく思いました。

template<typename Object>
struct Bar
{
    typedef int (Object::*Sig)(int);
};

Bar<Baz>;                // Sig will be `int (Baz::*)(int)`
Bar<const Baz>;          // Sig will be `int (Baz::*)(int) const`
Bar<volatile Baz>;       // Sig will be `int (Baz::*)(int) volatile`
Bar<const volatile Baz>; // Sig will be `int (Baz::*)(int) const volatile`

これは、すべてのケースを手動で書き出すよりもはるかに優れています。

&残念ながら、とでは機能しないようです&&

GCC 4.7 は次のように述べています。

エラー: 参照型 'Baz&&' へのポインターを形成しています</p>

しかし、4.7 の時点で GCC が の参照修飾子をまだサポートしていないことを考えると、これはそれほど驚くべきことではありませんthis

また、そのようなサポートがあるClang 3.0でも試しました。

エラー: メンバー ポインターが非クラス型 'Baz &&' を参照しています

しかたがない。

this typeこれは不可能であり、メンバー関数ポインターの " " で参照修飾子を抽象化する方法はないと結論付けて正しいでしょうか? テンプレートパラメータとしてthis「タイプ」を渡す特定のケース以外の修飾子(特に on )を抽象化するための他のテクニックも高く評価されます。this

(C++ がメンバー関数と通常の関数を区別していない場合、これはすべて些細なことであることに注意してください。テンプレート パラメーターを関数のパラメーター (ポインター) の型として使用すると、テンプレート引数は次のようになります。修飾子はそのままで、余計なことを考える必要はありません。)

4

1 に答える 1

4

テンプレートを単に特殊化することを考えたことがありますか?

2 つのバージョンを追加するだけです。

template <typename Object>
struct Bar<Object&> {
  typedef int (Object::*Sig)(int)&;
};

template <typename Object>
struct Bar<Object&&> {
  typedef int (Object::*Sig)(int)&&;
};

そして、コンパイラは適切な特殊化 (または一般的なケースへのフォールバック) を適切に選択します。

constこれは/のことからあなたを救いますがvolatile、コードを 3 回書く必要があることを意味します。

于 2012-01-15T20:03:33.047 に答える