在 .h/.cpp 文件中支持不同版本的 boost
Supporting different versions of boost in .h/.cpp files
我有一个头文件和 .cpp 文件(称之为 Foo.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;
}
问题是现在我需要支持不支持 bimap 的较早版本的 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()函数declaration/definition只存在于后来的boost版本场景中(这两个场景不是100%一致的)。我知道 GetMessageIDToStringMap() 函数本身对于早期的提升版本方案将永远不需要。
理想情况下,我想将静态 bimap 留在 .cpp 文件中,并将 GetMessageIDToStringMap() 移动到另一个文件中的某处,以便 Foo.h/.cpp 对于每个 #ifdef 块都是 100% 一致的。问题是 bimap 是 .cpp 文件中的静态变量,没有其他文件可以访问它。即使我将 bimap 设为全局变量而不是静态变量,我现在也必须在头文件中公开一个全局变量,该变量将再次只存在于更高版本的 boost 中。
有没有办法解决这个问题,使文件的两个版本(boost >= 1.35 与早期的 boost)始终 100% 一致,但 GetMessageIDToStringMap() 函数在另一个文件中可用?
回复问题中的评论:
在 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.
但正如我在第一条评论中所说,我更喜欢单身 class。
我有一个头文件和 .cpp 文件(称之为 Foo.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;
}
问题是现在我需要支持不支持 bimap 的较早版本的 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()函数declaration/definition只存在于后来的boost版本场景中(这两个场景不是100%一致的)。我知道 GetMessageIDToStringMap() 函数本身对于早期的提升版本方案将永远不需要。
理想情况下,我想将静态 bimap 留在 .cpp 文件中,并将 GetMessageIDToStringMap() 移动到另一个文件中的某处,以便 Foo.h/.cpp 对于每个 #ifdef 块都是 100% 一致的。问题是 bimap 是 .cpp 文件中的静态变量,没有其他文件可以访问它。即使我将 bimap 设为全局变量而不是静态变量,我现在也必须在头文件中公开一个全局变量,该变量将再次只存在于更高版本的 boost 中。
有没有办法解决这个问题,使文件的两个版本(boost >= 1.35 与早期的 boost)始终 100% 一致,但 GetMessageIDToStringMap() 函数在另一个文件中可用?
回复问题中的评论:
在 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.
但正如我在第一条评论中所说,我更喜欢单身 class。