私はcerealとboost::serializationコードを見て、クラス登録の仕組みを理解していますが、瞬時には理解できません。これはどのように機能しますか?
- を私は
static_object<magic<B№>>
の明示的なインスタンス化を要求:はここで何が起こるか私の理解です。
- コンストラクタ内に
adl_magic
が存在するため、コンパイラはすべてのオーバーロードをインスタンス化します。 - これらのオーバーロードの一部の戻り値の型は
typename instantiator<inserter<A№, T>>::type
を参照するため、コンパイラはインスタンスinstantiator
(意図しない句)を作成します。 - 今、私は次に何が起こるのか分かりません。
static_object<nserter<A№, T>>
は、決して呼び出されない関数の内部から参照されていますが、なぜインスタンス化されますか?そして、なぜdummy
が必要なのですか(なぜ異なるコンパイラが別のものを必要とするのですか)?typename instantiator<inserter<A№, T>>::type
をtypename static_object<inserter<A№, T>>::type
に置き換えても、なぜ機能しないのですか?
残りのコードはかなりわかりやすいようです。
template<typename T>
class static_object {
static void use(T const&) {}
static T& ref;
static T& create()
{
static T object;
use(ref); // why it doesn't work without this line?
return object;
}
public:
static T& instance() { return create(); }
};
template <class T>
T& static_object<T>::ref = static_object<T>::create();
template <void(*)()> struct instantiate_function {};
template<typename T>
struct instantiator {
static void instantiate() { static_object<T>::instance(); }
#ifdef _MSC_VER
virtual void dummy() { instantiate(); }
#else
using dummy = instantiate_function<instantiate>;
#endif
};
#include <string>
#include <vector>
// This gets called when stuff below is instantiated
using list = std::pair<std::string, std::string>;
using list = static_object<std::vector<string_pair>>;
template<typename A, typename B>
struct inserter {
inserter()
{
list::instance().push_back(std::pair{A::name, B::name});
}
};
// These are just some structs for demonstration.
struct A1 { static const char name[]; }; const char A1::name[] = "A1";
struct A2 { static const char name[]; }; const char A2::name[] = "A2";
struct B1 { static const char name[]; }; const char B1::name[] = "B1";
struct B2 { static const char name[]; }; const char B2::name[] = "B2";
struct B3 { static const char name[]; }; const char B3::name[] = "B3";
// I've omitted an "adl_tag" argument, which is needed to make
// sure ADL finds all overloads
template<typename T> void adl_magic(T*, int) {}
// each of these would be behind some REGISTER_ARCHIVE(A) macro
template<typename T> typename instantiator<inserter<A1, T>>::type adl_magic(T*, A1*);
template<typename T> typename instantiator<inserter<A2, T>>::type adl_magic(T*, A2*);
template<typename T>
struct magic {
magic()
{
adl_magic(static_cast<T*>(nullptr), 0);
}
};
// each of these would be behind some REGISTER_CLASS(B) macro
template struct static_object<magic<B1>>;
template struct static_object<magic<B2>>;
template struct static_object<magic<B3>>;
#include <iostream>
int main()
{
for(auto& p : list::instance())
std::cout << p.first << ' ' << p.second << '\n';
}
編集:私はこれらと上記対応する宣言を変更した場合、彼らはすべてのコンパイラで動作するように見えます。私はなぜ彼らが働くのかわかりませんが、auto
はstatic_object<T>
のインスタンス化を強制してタイプを推測するので、そうすると思います。唯一のGCCおよびない他のコンパイラで動作する別のバリエーションがあり、
template<typename T>
struct instantiator {
static auto instantiate() { return static_object<T>::instance(); }
};
template<typename T> decltype(instantiator<inserter<A1, T>>::instantiate()) adl_magic(T*, A1*);
template<typename T> decltype(instantiator<inserter<A2, T>>::instantiate()) adl_magic(T*, A2*);
:今
template<typename T>
struct instantiator {
static T& ref;
};
template<typename T>
T& instantiator<T>::ref = static_object<T>::instance();
template<typename T> decltype(instantiator<inserter<A1, T>>::ref) adl_magic(T*, A1*);
template<typename T> decltype(instantiator<inserter<A2, T>>::ref) adl_magic(T*, A2*);
8つの疑問符があるように見えるので、あなたの質問は非常に難しいようです。小さなコンパイル可能なサンプルを作成し、最小限の疑問符を付けることをお勧めします。 –
すべてのコードブロックを1つにまとめると、コンパイル可能な最小の例です。 – Hedede
@Johannes Schaub - litb、私は1つのブロックにコードを結合し、疑問符の量を減らしました。私は今、それを解析するのがより簡単で(そして難しくない)ことを願っています。 – Hedede