定义相互依赖的类的c++宏
C++ macro defining classes dependent on each other
我试图编写宏,定义两个紧密连接的类一次,但我不能。下面是我的代码:
#ifndef SIGNALS_HPP
#define SIGNALS_HPP
#include <unordered_set>
#include <cstdio>
/**
* Macro defines pair of classes, sender and receiver. When one of them is destroyed,
* all it's connections are dully unconnected.
*
* EXAMPLE:
*
* signal(SomeEvent, some_event_occured)
*
* EXPANDS TO:
*
* class SomeEventReceiver {
* protected:
* virtual void on_some_event_occured() {}
* }
*
* class SomeEventSender {
* public:
* void connect_some_event_occured(SomeEventReceiver & listener); // registers listener
* void unconnect_some_event_occured(SomeEventReceiver & listener); // forgets listener
*
* protected:
* void send_some_event_occured(); // notifies all listeners
* }
*/
#define signal(signal_name, slot_name)
class signal_name##Sender;
class signal_name##Receiver
{
friend class signal_name##Sender;
std::unordered_set<signal_name##Sender*> senders;
protected:
virtual void on_##slot_name() {}
public:
virtual ~signal_name##Receiver();
};
class signal_name##Sender
{
friend class signal_name##Receiver;
std::unordered_set<signal_name##Receiver*> listeners;
public:
virtual ~signal_name##Sender()
{
for (auto i : listeners)
i->senders.erase(this);
listeners.clear();
}
void connect_##slot_name(signal_name##Receiver & listener)
{
listeners.insert(&listener);
listener.senders.insert(this);
}
void unconnect_##slot_name(signal_name##Receiver & listener)
{
listeners.erase(&listener);
listener.senders.erase(this);
}
protected:
void send_##slot_name()
{
for (auto i : listeners)
i->on_##slot_name();
}
};
/* // <-------------- THE LAST SECTION
signal_name##Receiver::~signal_name##Receiver()
{
for (auto i : senders)
i->listeners.erase(this);
senders.clear();
}//*/
#endif // SIGNALS_HPP
1)为什么最后一部分被注释了?我认为所有的虚方法必须要么定义或纯?
2)这个宏在另一个头文件中使用。当最后一部分没有注释时,我收到了很多"多重定义"错误。我相信我知道为什么它不起作用:最后一节算作定义,不应该在标题。但是我如何实现这样的宏呢?或者如果我错了,真正的问题是什么?
快速用法示例:
#ifndef SOME_HPP
#define SOME_HPP
signal(AA, aa)
class X : public AASender {
};
#endif
如果在一些。cpp文件中包含这样的内容(可能是间接的),它会得到以下错误:"typeinfo for AAReceiver', first defined here, In function
~new_allocator"的多重定义:"。"typeinfo" varies to destructor and
类型名称和虚表。接收方有时会变成发送方。
如果一个人真的喜欢阅读,那就有真正的错误:
army.o: In function `~BattleEndaaaaaaaReceiver':
/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: multiple definition of `BattleEndaaaaaaaReceiver::~BattleEndaaaaaaaReceiver()'
province.o:/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: first defined here
army.o: In function `~new_allocator':
/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: multiple definition of `BattleEndaaaaaaaReceiver::~BattleEndaaaaaaaReceiver()'
province.o:/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: first defined here
army.o: In function `~new_allocator':
/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: multiple definition of `BattleEndaaaaaaaReceiver::~BattleEndaaaaaaaReceiver()'
province.o:/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: first defined here
army.o: In function `std::__detail::_Hashtable_alloc<std::allocator<std::__detail::_Hash_node<BattleEndaaaaaaaSender*, false> > >::_M_deallocate_nodes(std::__detail::_Hash_node<BattleEndaaaaaaaSender*, false>*)':
/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: multiple definition of `typeinfo for BattleEndaaaaaaaReceiver'
province.o:/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: first defined here
army.o: In function `~new_allocator':
/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: multiple definition of `typeinfo name for BattleEndaaaaaaaReceiver'
province.o:/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: first defined here
army.o: In function `~new_allocator':
/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: multiple definition of `vtable for BattleEndaaaaaaaReceiver'
province.o:/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: first defined here
game.o: In function `~BattleEndaaaaaaaReceiver':
/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: multiple definition of `BattleEndaaaaaaaReceiver::~BattleEndaaaaaaaReceiver()'
province.o:/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: first defined here
game.o: In function `new_allocator':
/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: multiple definition of `BattleEndaaaaaaaReceiver::~BattleEndaaaaaaaReceiver()'
province.o:/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: first defined here
game.o: In function `new_allocator':
/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: multiple definition of `BattleEndaaaaaaaReceiver::~BattleEndaaaaaaaReceiver()'
province.o:/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: first defined here
game.o: In function `vector':
/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: multiple definition of `typeinfo for BattleEndaaaaaaaReceiver'
province.o:/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: first defined here
game.o: In function `new_allocator':
/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: multiple definition of `typeinfo name for BattleEndaaaaaaaReceiver'
province.o:/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: first defined here
game.o: In function `new_allocator':
/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: multiple definition of `vtable for BattleEndaaaaaaaReceiver'
province.o:/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: first defined here
gamemapwidget.o: In function `~BattleEndaaaaaaaReceiver':
/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: multiple definition of `BattleEndaaaaaaaReceiver::~BattleEndaaaaaaaReceiver()'
province.o:/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: first defined here
gamemapwidget.o: In function `new_allocator':
/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: multiple definition of `BattleEndaaaaaaaReceiver::~BattleEndaaaaaaaReceiver()'
province.o:/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: first defined here
gamemapwidget.o: In function `new_allocator':
/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: multiple definition of `BattleEndaaaaaaaReceiver::~BattleEndaaaaaaaReceiver()'
province.o:/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: first defined here
gamemapwidget.o: In function `std::_Hashtable<BattleEndaaaaaaaReceiver*, BattleEndaaaaaaaReceiver*, std::allocator<BattleEndaaaaaaaReceiver*>, std::__detail::_Identity, std::equal_to<BattleEndaaaaaaaReceiver*>, std::hash<BattleEndaaaaaaaReceiver*>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, true, true> >::_M_erase(std::integral_constant<bool, true>, BattleEndaaaaaaaReceiver* const&)':
/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: multiple definition of `typeinfo for BattleEndaaaaaaaReceiver'
province.o:/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: first defined here
gamemapwidget.o: In function `new_allocator':
/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: multiple definition of `typeinfo name for BattleEndaaaaaaaReceiver'
province.o:/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: first defined here
gamemapwidget.o: In function `new_allocator':
/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: multiple definition of `vtable for BattleEndaaaaaaaReceiver'
province.o:/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: first defined here
battle.o: In function `~BattleEndaaaaaaaReceiver':
/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: multiple definition of `BattleEndaaaaaaaReceiver::~BattleEndaaaaaaaReceiver()'
province.o:/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: first defined here
battle.o: In function `~new_allocator':
/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: multiple definition of `BattleEndaaaaaaaReceiver::~BattleEndaaaaaaaReceiver()'
province.o:/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: first defined here
battle.o: In function `~new_allocator':
/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: multiple definition of `BattleEndaaaaaaaReceiver::~BattleEndaaaaaaaReceiver()'
province.o:/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: first defined here
battle.o: In function `std::__detail::_Hashtable_alloc<std::allocator<std::__detail::_Hash_node<BattleEndaaaaaaaSender*, false> > >::_M_deallocate_nodes(std::__detail::_Hash_node<BattleEndaaaaaaaSender*, false>*)':
/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: multiple definition of `typeinfo for BattleEndaaaaaaaReceiver'
province.o:/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: first defined here
battle.o: In function `~new_allocator':
/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: multiple definition of `typeinfo name for BattleEndaaaaaaaReceiver'
province.o:/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: first defined here
battle.o: In function `~new_allocator':
/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: multiple definition of `vtable for BattleEndaaaaaaaReceiver'
province.o:/home/michal/Dokumenty/Projekty/build-Universania-Desktop-Debug/../Universania/battle.hpp:10: first defined here
clang: error: linker command failed with exit code 1 (use -v to see invocation)
头文件中的行外函数定义将与包含该头文件的每个编译单元一起发出,因此有多个定义。只要把它改成inline
就可以了。
顺便说一句,这与你的宏无关。在c++中应该避免使用宏。除了include保护和条件编译之外,c++中几乎没有什么有意义的宏用法。模板可以更好地完成许多事情。
相关文章:
- 如何从C++中的依赖类型中获得它所依赖的类型
- 将--whole archive链接器选项与CMake和具有其他库依赖项的库一起使用
- 将依赖名称显式标记为类型名和模板的奇怪之处
- 在 Windows 上,是否可以让 dll 在不使用 PATH 环境变量的情况下在另一个文件夹中查找依赖项?
- C++GTKMM gui循环依赖关系
- 通过ccmake在cmake中缓存依赖选项
- 当基类是依赖类型时,这是一个缺陷吗
- 从不同的附加依赖项中识别等同命名的函数
- 如何在 CMake 中对目标依赖项进行分组?
- 是否可以依赖函数范围的静态变量来执行程序关闭期间调用的方法?
- 为什么构建目录中新构建的共享库与安装目录中的副本具有不同的依赖项集?
- VS 2015 链接错误 无法构建依赖于 libcurl 的项目
- 通过依赖类型使用非类型模板参数的单类型模板参数类模板的部分专用化
- 为什么内存屏障依赖于变量?
- node-gyp 的先有鸡还是先有蛋的问题:指向依赖项中的头文件
- 反转依赖于 end() 的迭代器
- GCC,CMake,预编译标头和维护依赖项
- 使用 'typename' 关键字将非类型视为依赖上下文中的类型
- 使用 Git 处理 C++ Visual Studio 2019 解决方案的外部依赖项源代码管理的最佳方法是什么?
- 为什么依赖模板类型在部分专用化中不可推导?