【发布时间】:2019-09-27 03:07:27
【问题描述】:
错误 LNK2005 "void __cdecl Command::addCommand(struct Command::Command)" (?addCommand@Command@@YAXU11@@Z) 已在 main.cpp.obj D:\Code\cpp\ 中定义discord\DexunBot\MainBot\CMakeLists.txt D:\Code\cpp\discord\DexunBot\MainBot\dexun_client.cpp.obj 1
错误 LNK2005 "void __cdecl CommandHandler::RegisterCommands(void)" (?RegisterCommands@CommandHandler@@YAXXZ) 已在 main.cpp.obj D:\Code\cpp\discord\DexunBot\MainBot\CMakeLists 中定义.txt D:\Code\cpp\discord\DexunBot\MainBot\dexun_client.cpp.obj 1
错误 LNK2005 "void __cdecl CommandHandler::CheckExecuteCommand(class DexunClientClass &,struct SleepyDiscord::Message)" (?CheckExecuteCommand@CommandHandler@@YAXAEAVDexunClientClass@@UMessage@SleepyDiscord@@@Z) 已在 main 中定义。 cpp.obj D:\Code\cpp\discord\DexunBot\MainBot\CMakeLists.txt D:\Code\cpp\discord\DexunBot\MainBot\dexun_client.cpp.obj 1
错误 LNK2005 "class std::unordered_map,class std::allocator >,struct Command::Command,struct std::hash,class std::allocator > >,struct std::equal_to,class std ::allocator > >,class std::allocator,class std::allocator > const ,struct Command::Command> > > Command::all" (?all@Command@@3V?$unordered_map@V?$basic_string@ DU?$char_traits@D@std@@V?$allocator@D@2@@std@@UCommand@3@U?$hash@V?$basic_string@DU?$char_traits@D@std@@V?$ allocator@D@2@@std@@@2@U?$equal_to@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@V ?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@UCommand@3@@std@@@2@ @std@@A) 已经定义在 main.cpp.obj D:\Code\cpp\discord\DexunBot\MainBot\CMakeLists.txt D:\Code\cpp\discord\DexunBot\MainBot\dexun_client.cpp.obj 1
在尝试编译我的项目时,我遇到了一些链接器错误。
我已经尝试将我的 command.hpp 也分离到一个 command.cpp 文件中,但我会收到诸如 std::function 不存在或类似的错误。
// command.hpp
class DexunClientClass;
namespace Command {
using Verb = std::function<
void(
DexunClientClass&,
SleepyDiscord::Message&,
std::queue<std::string>&
)
>;
struct Command {
std::string name;
std::vector<std::string> params;
std::string description;
Verb verb;
};
using MappedCommands = std::unordered_map<std::string, Command>;
using MappedCommand = MappedCommands::value_type;
MappedCommands all;
void addCommand(Command command) {
all.emplace(command.name, command);
}
}
// command_handler.hpp
#include "sleepy_discord/sleepy_discord.h"
#include "commands/help_command.hpp"
#include "dexun_client.hpp"
namespace CommandHandler {
void RegisterCommands() {
HelpCommand helpCommand;
helpCommand.registerHelpCommand();
}
void CheckExecuteCommand(DexunClientClass& client, SleepyDiscord::Message message) {
client.sendMessage(message.channelID, "WFAWFWF");
}
}
// dexun_client.hpp
#include "sleepy_discord/websocketpp_websocket.h"
class DexunClientClass : public SleepyDiscord::DiscordClient {
public:
using SleepyDiscord::DiscordClient::DiscordClient;
void onMessage(SleepyDiscord::Message message) override;
};
// dexun_client.cpp
#include "dexun_client.hpp"
#include "command.hpp"
#include "command_handler.hpp"
std::queue<std::string> split(const std::string& source) {
std::stringstream ss(source);
std::string item;
std::queue<std::string> target;
while (std::getline(ss, item, ' '))
if (!item.empty())
target.push(item);
return target;
}
void DexunClientClass::onMessage(SleepyDiscord::Message message) {
if (message.startsWith("dexun") || message.startsWith("dex")) {
CommandHandler::CheckExecuteCommand(*this, message);
std::queue<std::string> parameters = split(message.content);
const std::string mention = "<@" + message.author.ID + ">";
const std::string mentionNick = "<@!" + message.author.username + ">";
if (
//only allow if has more then 1 parameter
parameters.size() <= 1 &&
//only allow if starts with a mention
(parameters.front() != mention || parameters.front() != mentionNick)
)
return;
//remove the parameters as we go
parameters.pop();
if (parameters.empty())
return;
//get command
Command::MappedCommands::iterator foundCommand =
Command::all.find(parameters.front());
if (foundCommand == Command::all.end()) {
sendMessage(message.channelID, "Error: Command not found");
return;
}
parameters.pop();
if (
parameters.size() <
foundCommand->second.params.size()
) {
sendMessage(message.channelID, "Error: Too few parameters");
return;
}
//call command
foundCommand->second.verb(*this, message, parameters);
}
}
// main.cpp
#include "dexun_client.hpp"
#include "command_handler.hpp"
int main() {
DexunClientClass client("token", 2);
CommandHandler::RegisterCommands();
std::cout << "Registered Commands" << std::endl;
client.run();
}```
【问题讨论】:
-
以强大的ODR 的名义,除非已采取措施防止重复,否则不应在标题中定义。在
Command::addCommand的情况下,做吸盘inline -
同上
CommandHandler::RegisterCommands和CommandHandler::CheckExecuteCommand,但我怀疑在 cpp 文件中定义它们可能会更好。他们看起来正在做的事情最好不要放在标题中,如果您在开发时更改它们,它们可能会减慢构建速度。 -
在编译和测试之前考虑少写代码。您可以更快地发现错误,并且不太可能重蹈覆辙。
标签: c++