0

私は C++11 で型記述子プロジェクトに取り組んでいます。型記述子の仕事は、クラス内のすべてのメンバーの型、サイズ、およびオブジェクトのベースからのオフセットを知ることです。多重継承や仮想メソッドを持つオブジェクトはサポートしていないので、今のところこれをもっと簡単にしています。目標は、記述子を使用してオブジェクトをシリアル化および非シリアル化できるようにすることです。

これは、可変個引数テンプレート、メンバーへのポインター、および私がよく知らない C++ のその他の機能などの機能をいじるためのペット プロジェクトであるため、boost::archiving のようなものに向ける必要はありません。:)

実際にメンバーを登録する方法は、boost::python::class_ の方法とよく似ています。

ClassDescriptor fooDesc( "Foo" );
fooDesc.addMember( "a", &Foo:: a );
fooDesc.addMember( "b", &Foo:: b );

// (abridged for clarity) :
template< typename ClassType, typename MemberType >
ClassDescriptor& ClassDescriptor::addMember(
  const char* name,
  MemberType ClassType::* member
)
{
   return addMember< MemberType >( name, reinterpret_cast< size_t >( &(((ClassType*)0)->*member)) );
}

残念ながら、今週初めに学んだように、C++ のポインターからメンバーへの機能は C++ の参照では使用できません: https://stackoverflow.com/a/8336479/1074536。たとえば、 &Foo::refToAndInt を使用します。

メンバーのオフセットを計算する方法に関しては、クラスが常に POD であるとは限らないため、マクロのオフセットを使用していません。

したがって、参照のオフセットを計算するためにメンバーへのポインターを使用できないため、次のことを試してみようと思いました。

&(((Foo*)nullptr)->refToAnInt)

しかし、別のスタック オーバーフロー スレッドで指摘されていますが、これは未定義の動作であり、明らかに LLVM ではクラッシュします。:(

前のメンバーのオフセットを取得し、そのサイズを追加してから、次のメンバーを整列させるために必要なパディングを何らかの方法で計算するようなことは避けたいと思います。

したがって、これらのトリックの両方を使用することはできず、offsetof は POD 専用です。私の他の恐ろしい提案とは別に、次に何を試すことができるかについて何か提案はありますか?

ありがとう!

4

1 に答える 1

0

規格によると、

  1. クラス

    6 ...自明なクラスは、自明なデフォルトコンストラクタ(12.1)を持つクラスであり、... ...

    10 POD 構造体は、自明なクラスであると同時に ... ...

12.1 コンストラクタ

5 ...

 A default default constructor for class X is defined as deleted if:

 ...

 - any non-static data member with no brace-or-equal-initializer is of

参照タイプ、

 ...

 A default constructor is trivial if it is neither user-provided nor deleted

で、もし

 ...

 - for all the non-static data members of its class that are of class type(or

その配列)、そのような各クラスには、単純なデフォルトのコンストラクターがあります。

確かに、brace-or-equal-initializer が存在しない限り、参照メンバーを持つクラスを POD にすることはできません。次に例を示します。

class A
{
    A &me=*this;
};

この場合、特定の回避策を作成できる場合があります。

の問題に対して

&(((Foo*)nullptr)->refToAnInt)

次のことを試すことができます。

std::aligned_storage<sizeof(Foo), std::alignment_of<Foo>::value>::type storage;
&((static_cast<Foo *>(static_cast<void *>(&storage)))->refToAnInt);

その動作は明確に定義されている必要があります。

于 2011-12-05T04:15:13.423 に答える