假设我有这样的东西:
template <typename T, typename ...args>
static std::map<T, std::tuple<args...>> MyMaps;
每种类型在编译时都是已知的。因此,对于添加到映射中的每个类型配置,都会创建一个新的映射。
是否有一种方法可以在所有与T参数匹配的map实例中仅使用键(和键类型)进行搜索?
编辑:很抱歉我的问题过于简单化了。我害怕把它做得太大,最后它偏离了我的意图。但我想我想要达到的目标是不可能的,就像@Quimby解释的那样。我真正想做的是一个调试助手(实际上是虚幻的),跟踪对象值类似于可包含的。h (debughelper .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。
No.
必须解决的基本问题是确定模板变量是否已实例化。否则,在无限多个可能的实例中进行有趣的搜索。
c++没有提供回答这些问题的工具,因为实现几乎是不可能的。主要是由于编译和链接过程是分开的。TL;博士;可能是翻译单元(TU)还没有包含足够的信息,并且链接器太晚了,因为代码已经生成了。
每个翻译单元单独编译成一个目标文件。每个TU看到(希望是相同的)模板定义,它从模板定义中实例化了本TU中使用的所有变量,但它不知道也不可能知道其他TU中的任何实例化变量。
链接器的工作是收集所有这些目标文件,解析导出和缺失的符号,包括inline
定义的重复删除,最后创建可执行文件/库。
只有在最后一步之前,这个问题才能得到答案。但是此时,代码已经生成,无法更改。即使它可以让编译器再次创建新代码,如果新代码产生更多的实例化,链接器应该再试一次吗?
这取决于你对搜索的定义。您可以将它们收集到一个容器中,然后进行任何您喜欢的处理:
#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';
}