Ошибка компоновщика: не удалось разрешить конструктор - PullRequest
0 голосов
/ 20 января 2020

Впервые до 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": []
    }
  ]
}

1 Ответ

6 голосов
/ 20 января 2020

[basi c .def.odr] / 4 ... Встроенная функция или переменная должны быть определены в каждой единице перевода, в которой она используется odr, за исключением отброшенного оператор.

Определение SmsMsg помечено inline, но оно не отображается в единице перевода, где оно используется. Ваша программа нарушает одно правило определения и поэтому неправильно сформирована. Ключевое слово

inline обычно используется с функциями, определенными в заголовках. Не имеет смысла помещать его в определение функции в исходном файле.

...