2015-01-19 2 views
0

У меня есть заголовок и .cpp-файл (назовите его Foo.h/.cpp), который структурирован так (без лишних деталей для простоты):Поддержка различных версий boost в файлах .h/.cpp

foo.h

#include <boost/bimap.hpp> 

const std::string & ToHeader(const int msgID); 
int ToMsgID(const std::string & msgHdr); 

typedef boost::bimap<int, std::string> MsgIDBimap; 
MsgIDBimap & GetMessageIDToStringMap(); 

foo.cpp

#include "Foo.h" 
#include <boost/assign/list_of.hpp> 

static MsgIDBimap msgIDBimap = boost::assign::list_of<MsgIDBimap::relation> 
    ((int)ROM_MSG, "") 
    ... // a whole bunch of other entries 
; // end static bimap initialization 

const std::string & ToHeader(const int msgID) 
{ 
    MsgIDBimap::left_iterator foundIT = msgIDBimap.left.find(msgID); 
    if(foundIT != msgIDBimap.left.end()) // found 
    { 
     return foundIT->second; 
    } 

    throw std::string("MSG_ID_NOT_FOUND"); 
} 

int ToMsgID(const std::string & msgHdr) 
{ 
    int msgID = (int)MSG_UNKNOWN; // unknown message header 
    MsgIDBimap::right_iterator foundIT = msgIDBimap.right.find(msgHdr); 
    if(foundIT != msgIDBimap.right.end()) // found 
    { 
     msgID = foundIT->second; 
    } 
    return msgID; 
} 

MsgIDBimap & GetMessageIdToStringMap() 
{ 
    return msgIDBimap; 
} 

проблема заключается в том, что теперь мне нужно поддерживать более ранняя версия boost, которая не поддерживает бимап (отстой, я знаю ... но у меня нет выбора). До сих пор, это мое решение:

foo.h

#include <boost/version.hpp> 
#define BOOST_VER_MAJOR (BOOST_VERSION/100000)  // ex.: 1 in 1_37_0 
#define BOOST_VER_MINOR ((BOOST_VERSION/100) % 1000) // ex.: 37 in 1_37_0 
#define BOOST_VER_PATCH (BOOST_VERSION % 100)   // ex.: 0 in 1_37_0 

/*************************************************************************************************/ 
#if ((BOOST_VER_MAJOR >= 1) && (BOOST_VER_MINOR >= 35)) // boost greater than or equal to 1.35 (bimap available) 
#include <boost/bimap.hpp> 
#endif 
/*************************************************************************************************/ 

const std::string & ToHeader(const int msgID); 
int ToMsgID(const std::string & msgHdr); 

/*************************************************************************************************/ 
#if ((BOOST_VER_MAJOR >= 1) && (BOOST_VER_MINOR >= 35)) // boost greater than or equal to 1.35 (bimap available) 
typedef boost::bimap<int, std::string> MsgIDBimap; 
MsgIDBimap & GetMessageIdToStringMap(); 
#endif 
/*************************************************************************************************/ 

foo.cpp

#include "Foo.h" 
#include <boost/assign/list_of.hpp> 

#if ((BOOST_VER_MAJOR >= 1) && (BOOST_VER_MINOR >= 35)) // boost greater than or equal to 1.35 (bimap available) 

static MsgIDBimap msgIDBimap = boost::assign::list_of<MsgIDBimap::relation> 
    ((int)ROM_MSG,   "") // <ROM message> (no header) 

; // end static msgIDBimap initialization 

const std::string & ToHeader(const int msgID) 
{ 
    MsgIDBimap::left_iterator foundIT = msgIDBimap.left.find(msgID); 
    if(foundIT != msgIDBimap.left.end()) // found 
    { 
     return foundIT->second; 
    } 

    throw std::string("MSG_ID_NOT_FOUND"); 
} 

int ToMsgID(const std::string & msgHdr) 
{ 
    int msgID = (int)MSG_UNKNOWN; // unknown message header 
    MsgIDBimap::right_iterator foundIT = msgIDBimap.right.find(msgHdr); 
    if(foundIT != msgIDBimap.right.end()) // found 
    { 
     msgID = foundIT->second; 
    } 
    return msgID; 
} 

MsgIDBimap & GetMessageIdToStringMap() 
{ 
    return msgIDBimap; 
} 

/*************************************************************************************************/ 
#else // boost less than 1.35, bimap not available 

typedef std::map<int, std::string> MsgIDToStringMap; 
static MsgIDToStringMap msgIDToStringMap = boost::assign::map_list_of<int, std::string> 
    ((int)ROM_MSG,   "") // <ROM message> (no header) 
; // end static msgIDToStringMap initialization 

const std::string & ToHeader(const int msgID) 
{ 
    const MsgIDToStringMap::const_iterator foundIT = msgIDToStringMap.find(msgID); 
    if(foundIT != msgIDToStringMap.end()) // found 
    { 
     return foundIT->second; 
    } 

    throw std::string("MSG_ID_NOT_FOUND"); 
} 

#define FLIP_ARGS(x,y) (y,x) 
typedef std::map<std::string, int> StringToMsgIDMap; 
static StringToMsgIDMap stringToMsgIDMap = boost::assign::map_list_of<std::string, int> 
    FLIP_ARGS((int)ROM_MSG,   "") // <ROM message> (no header) 

; // end static stringToMsgIDMap initialization 

int ToMsgID(const std::string & msgHdr) 
{ 
    int msgID = (int)MSG_UNKNOWN; // unknown message header 
    const StringToMsgIDMap::const_iterator foundIT = stringToMsgIDMap.find(msgHdr); 
    if(foundIT != stringToMsgIDMap.end()) // found 
    { 
     msgID = foundIT->second; 
    } 
    return msgID; 
} 
#endif 

Хотя это работает, проблема заключается в том, что при объявлении функции GetMessageIDToStringMap()/definition существует только в более позднем сценарии ускоренной версии (два сценария не являются 100% конгруэнтными друг другу). Я знаю, что сама функция GetMessageIDToStringMap() никогда не понадобится для более раннего сценария ускоренной версии.

В идеале, я хотел бы оставить статический бимап внутри .cpp-файла и переместить GetMessageIDToStringMap() в другой файл где-нибудь, чтобы Foo.h/.cpp были на 100% конгруэнтными для каждого блока #ifdef. Проблема в том, что бимап является статической переменной внутри .cpp-файла, и ни один другой файл не может получить к нему доступ. Даже если я делаю bimap глобальной переменной вместо статической переменной, теперь мне нужно выставить глобальную переменную в файле заголовка, которая снова будет существовать только в более поздних версиях boost.

Есть ли способ решить эту проблему, чтобы две версии файла (boost> = 1.35 по сравнению с предыдущим повышением) всегда были на 100% конгруэнтными друг к другу, и все же функция GetMessageIDToStringMap() доступна в другом файле?

+0

Глобальная переменная не должна отображаться в файле заголовка. вы можете использовать 'extern' в файле cpp. Я бы предпочел использовать классы singleton вместо globals или statics. – SHR

+0

Вы имеете в виду добавить ключевое слово extern в bimap, определенную в .cpp? – Andrew

ответ

0

В ответ на замечание в вопросе:

в foo.cpp:

typedef std::map<int, std::string> MsgIDToStringMap; 
//you can remove the static 
MsgIDToStringMap msgIDToStringMap = ... 

Теперь в other.cpp файле:

extern MsgIDToStringMap msgIDToStringMap; 
//and you can use the global variable. 

Но, как я сказал в 1-й комментарий, я бы предпочел один класс.

+0

Кажется, что это сработает, но я беспокоюсь о том, как это повлияет на существующую функциональность. Этот класс находится в статическом lib, который ссылается на другие ссылки libs. Есть несколько приложений, которые мы используем для повторного использования библиотеки, которая содержит этот класс (приложение C# и 2 приложения на C++). Итак, изменив бимап как глобальный, а не статический, изменит ли это поведение каким-либо образом? – Andrew

+0

Добавление глобального или изменение глобального из статического, будет проблемой только в том случае, если в одном и том же пространстве имен есть глобальная или статическая переменная с тем же именем. – SHR

+0

Я просто попробовал это, и он компилируется.Я проведу несколько позже, когда моя среда разработки будет запущена и запущена. Я, вероятно, запустил это другими разработчиками в своей команде и посмотрю, что они думают. В любом случае, я продолжу и даю вам кредит на этот вопрос. Спасибо за вашу помощь! – Andrew