11

次の縮小されたコードサンプルは、有用なことは何もしませんが、データメンバーポインタへの2つの後続の割り当てを行います。最初の割り当ては機能し、2番目の割り当てはコンパイラエラーを発生させます。おそらく、ネストされたメンバーにあるためです。

質問は次のようになります。メンバーポインタがネストされたメンバーを指すようにすることは本当に不可能ですか、それともそこに凝った構文がありませんか?

struct Color {
    float Red;
    float Green;
    float Blue; };


struct Material {
    float Brightness;
    Color DiffuseColor; };


int main() {
    float Material::* ParamToAnimate;
    ParamToAnimate = &Material::Brightness;       // Ok
    ParamToAnimate = &Material::DiffuseColor.Red; // Error! *whimper*
    return 0; }

ATMバイトオフセットと多くのキャストを使用して回避しています。しかし、それは醜いので、それらのメンバーポインタを使用したほうがいいです。

はい、私はその質問が確かに以前に発生したことを知っています(ほとんどすべての質問のように)。はい、事前に検索しましたが、満足のいく答えは見つかりませんでした。

御時間ありがとうございます。

4

8 に答える 8

5

datamember へのポインターを取得しようとしていると思いますRed。this は構造体で定義されているためColor、ポインターの型は ですColor::*。したがって、コードは次のようになります。

int main() {
    float Color::* ParamToAnimate;
    ParamToAnimate = &Color::Red; 
    return 0; }

Colorそれを使用するには、たとえば次のインスタンスにバインドする必要があります。

void f(Color* p, float Color::* pParam)
{
    p->*pParam = 10.0;
}
int main() {
    float Color::* ParamToAnimate;
    ParamToAnimate = &Color::Red; 

    Material m;
    f(&m.DiffuseColor, ParamToAnimate);
    return 0;
}

EDIT:アニメーション機能をテンプレートにすることはできませんか?例えば:

template<class T>
void f(T* p, float T::* pParam)
{
    p->*pParam = 10.0;
}
int main() {

    Material m;

    f(&m.DiffuseColor, &Color::Red);
    f(&m, &Material::Brightness);
    return 0;
}
于 2010-08-09T10:31:49.387 に答える
4

私の知る限り、これは不可能です。メンバーへのポインターは、 type の式によってのみ形成でき&qualified_idますが、これはあなたの場合ではありません。

Vite Falcon のソリューションがおそらく最も適切です。

于 2010-08-09T10:36:15.330 に答える
3

メンバ ポインタの代わりに、 ;float*のインスタンスが与えられたときにを返すファンクタを使用できます。MaterialのタイプParamToAnimateを次のように変更します。

std::function<float*(Material&)>

プラス面では移植性がありますが、マイナス面としては、かなりの量の定型コードが必要で、実行時のオーバーヘッドがかなり大きくなります。

これがパフォーマンス上重要な場合は、オフセット方式を使いたくなるでしょう。

于 2010-08-09T11:26:32.407 に答える
1

基本的に、アニメーション化できる float 変数へのポインターを取得しようとしています。なぜ使用しないのですかfloat*。あなたが抱えている問題は、それBrightnessが Material のメンバーであるということですが、コンパイラにとってRedは のメンバーでColorあり、 ではありません。Materialを使用float*すると、問題が解決するはずです。

于 2010-08-09T10:32:31.613 に答える
0

合成ではなく継承はどうですか?

struct Color {
    float Red;
    float Green;
    float Blue; };

struct DiffuseColor : public Color {
    };

struct Material : public DiffuseColor {
    float Brightness; };


int main() {
    float Material::* ParamToAnimate;
    ParamToAnimate = &Material::Brightness;       // Ok
    ParamToAnimate = &Material::DiffuseColor::Red; // Ok! *whew*
    return 0; }
于 2011-05-01T00:36:27.333 に答える
0

ネストされた構造がまったくないように単純にリファクタリングできます。既存のコードをあまり変更する必要がないように、色をコンポーネント パーツにアンパックするよりもセッターを追加し、そこから先に進みます。

ネストされた型を掘り下げるオプションの 2 番目のポインターを使用することもできます。2 番目のパラメーターが必要かどうかを確認する単一のテストは、現在の方法と比較して十分であることが証明される可能性があり、後で追加のフィールドが表示された場合により簡単に拡張できます。

さらに一歩進めるMaterialPointerと、仮想Dereferenceメソッドを持つ基本クラスができます。ケース クラスは単純なメンバーを処理できます。派生クラスは、ネストされたメンバーを検索するために必要な追加情報と共に処理します。その後、ファクトリMaterialMember*は適切なタイプのオブジェクトを生成できます。もちろん、今はヒープ割り当てに行き詰まっているので、これは実用的であるには少し遠すぎる可能性があります。

于 2010-08-09T13:09:02.210 に答える
0

ある時点で実際のデータへのポインターが必要になるため、これが機能する場合と機能しない場合があります。

float Material::* ParamToAnimate;
ParamToAnimate = &Material::Brightness;       // Ok
float Color::* Param2;
Param2 = &Color::Red; 

Material mat;
mat.Brightness = 1.23f;
mat.DiffuseColor.Blue = 1.0f;
mat.DiffuseColor.Green = 2.0f;
mat.DiffuseColor.Red = 3.0f;

float f = mat.DiffuseColor.*Param2;
于 2010-08-09T15:39:57.660 に答える