【发布时间】:2020-05-06 15:08:32
【问题描述】:
cpp 新手。奇怪的是,我实际上在前一天设法编译了这个。但是今天突然不编译了,可能是因为一些缓存。清除 CMake 缓存后,我开始收到各种错误...
我定义了一个类:
#pragma once
#include <string>
#include <memory>
#include <boost/uuid/uuid.hpp>
#include "lib/Msg.hpp"
#include "lib/SplitParts.hpp"
namespace blz
{
class SmsMsg : Msg
{
public:
enum class SmsCoding { Undefined = -1, SevenBit, EightBit, Ucs2 };
enum class DcsEncodeMode { Undefined = -1, Default, Fx };
enum class Mwi { Undefined = -1, VoiceOn, FaxOn, EmailOn, OtherOn, VoiceOff, FaxOff, EmailOff, OtherOff };
enum class Mclass { Undefined = -1, Zero, One, Two, Three };
SmsMsg(boost::uuids::uuid id, int smsType, std::string& sender, std::string& receiver,
std::string& udhData, std::string& msgData, std::string& smscId, std::string& smscNumber,
std::string& foreignId, std::string& service, std::string& account, int time, Mclass mclass,
Mwi mwi, SmsCoding coding, bool compress, int validity, int deferred, int dlrMask, std::string& dlrUrl,
int pid, int altDocs, int rpi, std::string& charset, std::string& boxId, std::string& binInfo,
int msgLeft, std::unique_ptr<SplitParts> splitParts, int priority, int resendTry, int resendTime,
std::string& metaData);
int encodeDcs(DcsEncodeMode mode);
private:
boost::uuids::uuid id;
int smsType;
std::string sender;
std::string receiver;
std::string udhData;
std::string msgData;
std::string smscId;
std::string smscNumber;
std::string foreignId;
std::string service;
std::string account;
int time;
Mclass mclass;
Mwi mwi;
SmsCoding coding;
bool compress;
int validity;
int deferred;
int dlrMask;
std::string dlrUrl;
int pid;
int altDocs;
int rpi;
std::string charset;
std::string boxId;
std::string binfo;
int msgLeft;
std::unique_ptr<SplitParts> splitParts{};
int priority;
int resendTry;
int resendTime;
std::string metaData;
};
}
类的实现如下:
#include "SmsMsg.hpp"
inline blz::SmsMsg::SmsMsg(const boost::uuids::uuid id, const int smsType, std::string& sender, std::string& receiver,
std::string& udhData, std::string& msgData, std::string& smscId, std::string& smscNumber,
std::string& foreignId, std::string& service, std::string& account, const int time,
const Mclass mclass, const Mwi mwi, const SmsCoding coding, const bool compress,
const int validity, const int deferred, const int dlrMask, std::string& dlrUrl,
const int pid, const int altDocs, const int rpi, std::string& charset, std::string& boxId,
std::string& binInfo, const int msgLeft, std::unique_ptr<SplitParts> splitParts,
const int priority, const int resendTry, const int resendTime, std::string& metaData) :
id(id),
smsType(smsType),
sender(sender),
receiver(receiver),
udhData(udhData),
msgData(msgData),
smscId(smscId),
smscNumber(smscNumber),
foreignId(foreignId),
service(service),
account(account),
time(time),
mclass(mclass),
mwi(mwi),
coding(coding),
compress(compress),
validity(validity),
deferred(deferred),
dlrMask(dlrMask),
dlrUrl(dlrUrl),
pid(pid),
altDocs(altDocs),
rpi(rpi),
charset(charset),
boxId(boxId),
binfo(binInfo),
msgLeft(msgLeft),
splitParts(std::move(splitParts)),
priority(priority),
resendTry(resendTry),
resendTime(resendTime),
metaData(metaData)
{
}
int blz::SmsMsg::encodeDcs(const DcsEncodeMode mode)
{
auto dcs = 0;
if (coding == SmsCoding::Undefined)
{
coding = udhData.length() ? SmsCoding::EightBit : SmsCoding::SevenBit;
}
if (mwi != Mwi::Undefined)
{
dcs = static_cast<int>(mwi);
if (dcs & 0x04)
{
dcs = (dcs & 0x03) | 0xC0;
}
else
{
dcs = (dcs & 0x03) | 0x08;
dcs |= !msgData.length() ? 0xC0 : coding == SmsCoding::SevenBit ? 0xD0 : 0xE0;
}
}
else
{
if (mode == DcsEncodeMode::Default || mode == DcsEncodeMode::Undefined || coding == SmsCoding::Ucs2 || compress)
{
if (compress)
{
dcs |= 0x20;
}
if (mclass != Mclass::Undefined)
{
dcs |= (0x10 | static_cast<int>(mclass));
}
if (coding != SmsCoding::Undefined)
{
dcs |= (static_cast<int>(coding) << 2);
}
}
else
{
dcs |= 0xF0;
if (coding != SmsCoding::Undefined)
{
dcs |= (static_cast<int>(coding) << 2);
}
dcs |= mclass == Mclass::Undefined ? 1 : static_cast<int>(mclass);
}
}
return dcs;
}
Msg.hpp 和 SplitParts.hpp 只是空类,没有像 class Msg {} 和 class SplitParts {} 这样的实现。
然后我有一个像这样的测试类:
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include "SmsMsg.hpp"
#include "lib/SplitParts.hpp"
blz::SmsMsg getTestSms()
{
auto msgId = boost::uuids::uuid();
auto smsType = 1;
std::string sender = "blz";
std::string receiver = "48765432";
std::string udhData = "udhData";
std::string msgData = "Hello Foo!";
std::string smscId = "smscId";
std::string smscNumber = "smscNo";
std::string foreignId = "foreignId";
std::string service = "service";
std::string account = "account";
std::string dlrUrl = "http://example.com/dlr";
std::string charset = "ascii";
std::string boxId = "boxId";
std::string binInfo = "binInfo";
std::string metaData = "metaData";
auto time = 26748590;
auto mclass = blz::SmsMsg::Mclass::One;
auto mwi = blz::SmsMsg::Mwi::VoiceOn;
auto coding = blz::SmsMsg::SmsCoding::EightBit;
auto compress = true;
auto validity = 1;
auto deferred = 0;
auto dlrMask = 1;
auto pid = 1;
auto altDocs = 1;
auto rpi = 1;
auto msgLeft = 1;
auto splitParts = std::make_unique<blz::SplitParts>();
auto priority = 1;
auto resendTry = 1;
auto resendTime = 786545367;
return blz::SmsMsg(msgId, smsType, sender, receiver, udhData, msgData, smscId, smscNumber, foreignId, service,
account, time, mclass, mwi, coding, compress, validity, deferred, dlrMask, dlrUrl, pid, altDocs,
rpi, charset, boxId, binInfo, msgLeft, std::move(splitParts), priority, resendTry, resendTime, metaData);
}
TEST_CASE("Encode DCS using sms fields", "[sms]")
{
auto sms = getTestSms();
REQUIRE(sms.encodeDcs(blz::SmsMsg::DcsEncodeMode::Default) == 1);
}
我的项目结构:
project
|-------src
|------lib
|------ Msg.cpp
|------ Msg.hpp
|------ SplitParts.hpp
|------ SmsMsg.cpp
|------ SmsMsg.hpp
------ tests
|------ SmsMsgTest.cpp
------ CMakeLists.txt
CMakeLists.txt 的内容:
cmake_minimum_required(VERSION 3.15)
project(Blaze)
set(BLZ_HEADERS
"${CMAKE_CURRENT_SOURCE_DIR}/src/lib/Msg.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/lib/SplitParts.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/SmsMsg.hpp"
)
set(BLZ_SOURCES
"${CMAKE_CURRENT_SOURCE_DIR}/src/lib/Msg.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/SmsMsg.cpp"
)
set(BLZ_TESTS
"${CMAKE_CURRENT_SOURCE_DIR}/tests/Setup.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/tests/SmsMsgTest.cpp"
)
set(Boost_USE_STATICLIBS OFF)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
find_package(Boost 1.72.0 COMPONENTS system REQUIRED)
include_directories(${Boost_INCLUDE_DIRS})
add_library(Blz STATIC ${BLZ_HEADERS} ${BLZ_SOURCES})
target_link_libraries(Blz ${Boost_LIBRARIES})
### Tests
enable_testing()
find_package(Catch2 REQUIRED)
add_executable(BlzTests ${BLZ_TESTS})
target_include_directories(BlzTests PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
target_include_directories(BlzTests PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src/lib")
target_link_libraries(BlzTests Blz)
target_link_libraries(BlzTests Catch2::Catch2)
include(CTest)
include(Catch)
catch_discover_tests(BlzTests)
我得到的错误是:
Error LNK2019 unresolved external symbol "public: __cdecl blz::SmsMsg::SmsMsg(struct boost::uuids::uuid,int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &,int,enum blz::SmsMsg::Mclass,enum blz::SmsMsg::Mwi,enum blz::SmsMsg::SmsCoding,bool,int,int,int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &,int,int,int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &,int,class std::unique_ptr<class blz::SplitParts,struct std::default_delete<class blz::SplitParts> >,int,int,int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &)" (??0SmsMsg@blz@@QEAA@Uuuid@uuids@boost@@HAEAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@11111111HW4Mclass@01@W4Mwi@01@W4SmsCoding@01@_NHHH1HHH111HV?$unique_ptr@VSplitParts@blz@@U?$default_delete@VSplitParts@blz@@@std@@@6@HHH1@Z) referenced in function "class blz::SmsMsg __cdecl getTestSms(void)" (?getTestSms@@YA?AVSmsMsg@blz@@XZ)
我正在使用 Visual Studio IDE CMakeconfig:
{
"configurations": [
{
"name": "x64-Debug",
"generator": "Ninja",
"configurationType": "Debug",
"inheritEnvironments": ["msvc_x64_x64"],
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "-v",
"ctestCommandArgs": "",
"cmakeToolchain": "C:/Users/xxxx/.vcpkg/scripts/buildsystems/vcpkg.cmake",
"variables": []
}
]
}
【问题讨论】:
-
新用户?命名空间、提升、测试用例、配置……哇!我希望我刚接触 cpp 时也是这样
-
@ArdentCoder 我想这是一种恭维。好吧,我对编程并不陌生。我来自 C#,所以我花了很多时间研究这个类,通过测试尝试以类似于我做 C# 的方式设计它。
-
无论您是否是 C++ 新手,无论使用哪种计算机语言,一个函数都不应该采用数不胜数的参数。不用看,构造函数中的第 11 个参数表示什么?明白了吗?通常所做的是传递一个
struct,其成员具有一致的默认值。然后用户自定义这个结构的一个实例,然后将它发送给构造函数。 -
将所有这些参数放入一个实体(结构)中。那么构造函数将只接受一个参数,而不是 20 或 30。调用结构
SMSInformation或类似的东西。此外,由于参数的数量,代码会导致许多代码审查失败,甚至自动代码“检查员”会发出危险信号。老实说,将代码保持在那种状态是不值得的。 -
@swdon 当然,这是一种恭维。但是,您的代码可读性仍有一些改进空间。例如,考虑在函数参数数量非常多时将它们封装到有意义的容器中。无论如何,我再次赞扬你在从一种语言过渡到另一种语言方面的技能!