仅从一个模板参数中查找特定模板。可能吗?
Finding a specific template from just one template parameter. Is it possible?
假设我有这样的东西:
template <typename T, typename ...args>
static std::map<T, std::tuple<args...>> MyMaps;
每种类型在编译时都是已知的。因此,对于添加到地图的每个类型配置,都会创建一个新地图。
有没有一种方法可以在所有与 T 参数匹配的映射实例中仅使用键(和键类型)进行搜索?
编辑:很抱歉超级简化了我的问题。我害怕把它弄得太大,最后它没有达到我的意图。
但是我想我想要达到的目标是不可能的,就像@Quimby 解释的那样。
我真正想做的是一个调试助手(实际上是虚幻引擎),用于跟踪对象值,类似于这样的可包含 .h (debbughelper.h):
#include <tuple>
#include <vector>
#include <type_traits>
#define WATCHMYOBJECT(object, ...) //TO DO
#define RESCANMYOBJECT(object) //TO DO
template <typename ...T>
void Expand(T...args)
{
return;
}
template <typename T, typename ...args>
class MyWatcherClass
{
public:
static void WatchMyObject(T &object, args& ...b);
static void RescanMyObject(T& MyObject);
static std::vector<MyWatcherClass*> Instaces;
private:
std::tuple<args...> MyTuple = std::tuple<args...>();
std::vector<void*> VoidPointerStorage;
T* MyObjectPointer;
private:
MyWatcherClass();
~MyWatcherClass();
};
template <typename T, typename ...args>
void MyWatcherClass<T, args...>::WatchMyObject(T &MyObject, args& ...b)
{
MyWatcherClass<T, args...>* MyClassPointer = new MyWatcherClass;
InstacedObjects.push_back(MyClassPointer);
MyObjectPointer = &MyObject;
int helpint = 0;
MyClassPointer->MyTuple = std::make_tuple(b...);
Expand((MyClassPointer->PointerStorage.push_back((void*)&b),1)...);
}
template <typename T, typename ...args>
void MyWatcherClass<T, args...>::RescanMyObject(T &MyObject)
{
// I have yet to implement, but impossible to call this
// Compare Instaces[i].MyObjectPointer with &MyObject to find the matching one
// cast all the void pointers in std::vector<void*> VoidPointerStorage back to typed pointers using the tuple types
// Get the values derefing the pointers and update on the screen, log, etc
}
然后,在一些宏魔法的帮助下,有人可以做到:
// #include <"debbughelper.h">
class MyNormalClass
{
public:
MyNormalClass(int _MyInt, float _MyFloat, std::string _MyString);
int MyInt;
float MyFloat;
std::string MyString;
};
MyNormalClass::MyNormalClass(int _MyInt, float _MyFloat, std::string _MyString) : MyInt(_MyInt), MyFloat(_MyFloat), MyString(_MyString)
{
}
int main()
{
MyNormalClass MyObject = MyNormalClass(1, 5.2f, std::string("hello"));
WATCHMYOBJECT(MyObject, MyObject.MyInt, MyObject.MyFloat, MyObject.MyString);
// do other stuff
RESCANMYOBJECT(MyObject); //easy, without the need to retype all the members
}
但是如果没有成员的类型,就无法调用 RescanMyObject。
没有
必须解决的根本问题是确定模板变量是否已实例化。否则,在无限多的可能实例中搜索会很有趣。
C++ 不提供回答此类问题的工具,因为实现几乎是不可能的。主要是由于分开的编译和链接过程。 TL;DR; 可能是翻译单元 (TU) 还没有包含足够的信息,链接器来不及了,因为代码已经生成了。
每个翻译单元被单独编译成一个目标文件。每个 TU 都看到(希望是相同的)模板定义,它从中实例化了该 TU 中使用的所有变量。但它不知道也不能知道其他 TU 中的任何实例化变量。
链接器的工作是收集所有这些目标文件,解析导出和丢失的符号,包括删除 inline
定义的重复项,最后创建 executable/library.
只有在最后一步之前,问题才能得到解答。但此时,代码已经生成,无法更改。 即使它可能涉及编译器再次创建新代码,如果新代码生成更多实例化,链接器是否应该再次尝试?这与运行时反射接壤。
取决于您所说的搜索是什么意思。您可以将它们收集到一个容器中,然后进行任何您喜欢的处理:
#include <any>
#include <iostream>
#include <map>
#include <typeindex>
#include <vector>
std::map<std::type_index, // key type
std::vector<std::any> // pointers to the maps with this key type
>
key_to_map;
template <typename T, typename... args>
auto& MyMap() {
static std::map<T, std::tuple<args...>> map = [] {
key_to_map[std::type_index(typeid(T))].push_back(&map);
return decltype(map){};
}();
return map;
}
int main() {
MyMap<int, char, double>();
MyMap<char, int, double>();
MyMap<int, short, long>();
std::cout << "Number of maps with `int` as the key is "
<< key_to_map[std::type_index(typeid(int))].size() << '\n';
}
假设我有这样的东西:
template <typename T, typename ...args>
static std::map<T, std::tuple<args...>> MyMaps;
每种类型在编译时都是已知的。因此,对于添加到地图的每个类型配置,都会创建一个新地图。
有没有一种方法可以在所有与 T 参数匹配的映射实例中仅使用键(和键类型)进行搜索?
编辑:很抱歉超级简化了我的问题。我害怕把它弄得太大,最后它没有达到我的意图。 但是我想我想要达到的目标是不可能的,就像@Quimby 解释的那样。
我真正想做的是一个调试助手(实际上是虚幻引擎),用于跟踪对象值,类似于这样的可包含 .h (debbughelper.h):
#include <tuple>
#include <vector>
#include <type_traits>
#define WATCHMYOBJECT(object, ...) //TO DO
#define RESCANMYOBJECT(object) //TO DO
template <typename ...T>
void Expand(T...args)
{
return;
}
template <typename T, typename ...args>
class MyWatcherClass
{
public:
static void WatchMyObject(T &object, args& ...b);
static void RescanMyObject(T& MyObject);
static std::vector<MyWatcherClass*> Instaces;
private:
std::tuple<args...> MyTuple = std::tuple<args...>();
std::vector<void*> VoidPointerStorage;
T* MyObjectPointer;
private:
MyWatcherClass();
~MyWatcherClass();
};
template <typename T, typename ...args>
void MyWatcherClass<T, args...>::WatchMyObject(T &MyObject, args& ...b)
{
MyWatcherClass<T, args...>* MyClassPointer = new MyWatcherClass;
InstacedObjects.push_back(MyClassPointer);
MyObjectPointer = &MyObject;
int helpint = 0;
MyClassPointer->MyTuple = std::make_tuple(b...);
Expand((MyClassPointer->PointerStorage.push_back((void*)&b),1)...);
}
template <typename T, typename ...args>
void MyWatcherClass<T, args...>::RescanMyObject(T &MyObject)
{
// I have yet to implement, but impossible to call this
// Compare Instaces[i].MyObjectPointer with &MyObject to find the matching one
// cast all the void pointers in std::vector<void*> VoidPointerStorage back to typed pointers using the tuple types
// Get the values derefing the pointers and update on the screen, log, etc
}
然后,在一些宏魔法的帮助下,有人可以做到:
// #include <"debbughelper.h">
class MyNormalClass
{
public:
MyNormalClass(int _MyInt, float _MyFloat, std::string _MyString);
int MyInt;
float MyFloat;
std::string MyString;
};
MyNormalClass::MyNormalClass(int _MyInt, float _MyFloat, std::string _MyString) : MyInt(_MyInt), MyFloat(_MyFloat), MyString(_MyString)
{
}
int main()
{
MyNormalClass MyObject = MyNormalClass(1, 5.2f, std::string("hello"));
WATCHMYOBJECT(MyObject, MyObject.MyInt, MyObject.MyFloat, MyObject.MyString);
// do other stuff
RESCANMYOBJECT(MyObject); //easy, without the need to retype all the members
}
但是如果没有成员的类型,就无法调用 RescanMyObject。
没有
必须解决的根本问题是确定模板变量是否已实例化。否则,在无限多的可能实例中搜索会很有趣。
C++ 不提供回答此类问题的工具,因为实现几乎是不可能的。主要是由于分开的编译和链接过程。 TL;DR; 可能是翻译单元 (TU) 还没有包含足够的信息,链接器来不及了,因为代码已经生成了。
每个翻译单元被单独编译成一个目标文件。每个 TU 都看到(希望是相同的)模板定义,它从中实例化了该 TU 中使用的所有变量。但它不知道也不能知道其他 TU 中的任何实例化变量。
链接器的工作是收集所有这些目标文件,解析导出和丢失的符号,包括删除 inline
定义的重复项,最后创建 executable/library.
只有在最后一步之前,问题才能得到解答。但此时,代码已经生成,无法更改。 即使它可能涉及编译器再次创建新代码,如果新代码生成更多实例化,链接器是否应该再次尝试?这与运行时反射接壤。
取决于您所说的搜索是什么意思。您可以将它们收集到一个容器中,然后进行任何您喜欢的处理:
#include <any>
#include <iostream>
#include <map>
#include <typeindex>
#include <vector>
std::map<std::type_index, // key type
std::vector<std::any> // pointers to the maps with this key type
>
key_to_map;
template <typename T, typename... args>
auto& MyMap() {
static std::map<T, std::tuple<args...>> map = [] {
key_to_map[std::type_index(typeid(T))].push_back(&map);
return decltype(map){};
}();
return map;
}
int main() {
MyMap<int, char, double>();
MyMap<char, int, double>();
MyMap<int, short, long>();
std::cout << "Number of maps with `int` as the key is "
<< key_to_map[std::type_index(typeid(int))].size() << '\n';
}