这是如何运作的?(C 名称查找魔术)
How does this work? (C++ name lookup magic)
我一直在研究谷物和boost ::序列化代码,以了解班级注册的工作方式,但无法理解几点。
这是我的理解会发生什么:
- 我要求明确的
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
替换CC_7,为什么它不起作用?
对我来说,其余代码似乎很明显。
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>
的实例化推断类型。
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*);
还有另一种变化,仅适用于GCC,而不是其他编译器:
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*);
现在,我不明白接下来会发生什么。为什么它是从未被调用的函数的内部引用的,即使它是从未调用的?
发生实例化是因为::type
需要研究该类模板的专业化,因此必须实例化。
为什么需要假人(为什么不同的编译器需要不同的编译器(?
无法回答括号的部分,但是dummy
参考instantiate
,而其他任何事情都没有。必须参考instantiate
,以便编译器编译其中的代码。类模板的虚拟成员函数即使未使用,也总是会实例化的,因此可以解决问题。using
别名将函数的地址传递给另一个模板,该模板触发编译器以编译instantiate
ASWELL。
,如果我替换TypeName Instantiator> ::用TypeName static_object> :: type?type?
type,为什么它不起作用。
因为您已经实例化了static_object<T>
,但是只有实例化成员函数声明(例如虚拟成员函数或使用别名(和静态数据成员声明等。不是成员功能机构。因此,它不会触发static_object<...>
的静态数据成员的实例化,因此不会创建T
的对象,因此不会扩展list
。
use(ref); // why it doesn't work without this line?
因为instantiate
引用static_object<T>::instance
参考static_object<T>::create
参考... ref
通过将其传递给use
。如果删除了最后一件事,则不再需要ref
的存在,因此它将无法实例化。
- 正在查找文档以获得PS4平台的C++中的设备信息
- 在C++中查找文件
- 模板元程序查找相似的连续类型名称
- 在UNIX系统中使用DIR查找文件的字节大小
- 查找最接近的大于当前数字的数字的索引
- 有没有一种方法可以创建一个带有哈希表的数据库,该哈希表具有恒定时间查找功能
- 查找后更改类变量
- 使用正则表达式regex_search在字符串中查找字符串
- 使用gcc从静态链接的文件中查找可选符号
- 在C++中查找范围的长度
- 算法问题:查找从堆栈中弹出的所有序列
- 在Windows中查找扬声器输出的当前音量级别
- 如何在C++中使用X509证书模在令牌中查找私钥
- 使用.find函数在c++中查找字符和另一个字符之间的大小
- 在 Windows 上,是否可以让 dll 在不使用 PATH 环境变量的情况下在另一个文件夹中查找依赖项?
- 在 for 循环中查找问题时遇到困难
- 如何在文件中查找字节序列
- 试图创建一个多线程程序来查找0-100000000之间的总素数
- 使用堆查找第K个最大元素的时间复杂性
- 这是如何运作的?(C 名称查找魔术)