基于模板元编程技术的跨平台C++动态链接载入库。通过模板技术,使用者仅需通过简单的宏,就可以使编译器在编译期自己主动生成载入动态链接库导出符号的代码,无不论什么额外的执行时开销。

extern "C"
{
typedef int(*Proc_fnTestDll)();
typedef const char* (*Proc_fnTestDll2)(const char*);
} ASL_LIBRARY_BEGIN(Test)
// 强制载入名为fnTestDll的接口,假设没有该接口。则抛SymbolNotFound异常
ASL_SYMBOL_EXPLICIT(Proc_fnTestDll, fnTestDll)
// 载入名为<span style="font-family: Arial, Helvetica, sans-serif;">fnTestDll2的接口,假设没有该接口,则为NULL</span>
ASL_SYMBOL_OPTIONAL(Proc_fnTestDll2, fnTestDll2)
// 载入名为shouldFail的接口,假设没有该接口。则为NULL</span>
ASL_SYMBOL_OPTIONAL(Proc_fnTestDll2, shouldFail) // non-exists
// 载入名为testFunc的接口,接口函数的类型由调用时的实參类型决定
ASL_SYMBOL_EXPLICIT_T(testFunc) // Enabled only when ' #define ASL_USE_CPP11 1 ' and compliler supports c++ 11
ASL_LIBRARY_END() int _tmain(int argc, _TCHAR* argv[])
{
using namespace std; Test test; try {
test.Load(_T("testDll.dll"));
}
catch (const ASL::LibraryNotFoundException& e)
{
cout << "Lib not found " << e.what() << endl;
}
catch (const ASL::SymbolNotFoundException& e) {
cout << "Sym not found " << e.what() << endl;
} assert(test.shouldFail == NULL);
cout << test.fnTestDll() << endl;
cout << test.fnTestDll2("hELLO, WORLD") << endl;
// testFunc函数的签名由此处的实參类型推导出来,int为其返回值类型,
// 这样的调用方式并不安全。慎用!
cout << test.testFunc<int>(ASL_ARGS_T((int)1, (int)2.f)) << endl;
   test.Unload();
   getchar();
   return 0;
}

ASL_SYMBOL宏的第三个參数表示。假设该符号载入失败(模块并没有导出该接口),是否抛出SymbolNotFoundException。 为false时,抛出异常,终止链接库载入流程,而且e.what()为载入失败的符号名称。为true时,忽略错误,仍然继续载入其它符号。client能够依据相应的接口是否为NULL来推断该符号是否载入成功。

/********************************************************************
created: 2014/05/31
file base: AutoSharedLibrary
file ext: h
author: qiuhan (hanzz2007@hotmail.com) purpose: Cross platform classes and macros to make dynamic loaded module
easy to use by using c++ template meta-programming technic. No need to make any changes to existing module code. Support both windows(*.dll) and linux(*.so) platforms (wchar_t & char). SPECIAL THANKS TO TRL (Template Relection Library) usage:
Following codes are all in client side: ASL_LIBRARY_BEGIN(ClassName)
ASL_SYMBOL_OPTIONAL(Func1Type, func1)
ASL_SYMBOL_EXPLICIT(Func2Type, func2)
// Enabled only when ' #define ASL_USE_CPP11 1 ' and compliler supports c++ 11
ASL_SYMBOL_EXPLICIT_T(func4) // only need to declare the name
ASL_LIBRARY_END() ClassName theLib;
try {
theLib.Load("./1.so");
}
catch (LibraryNotFoundException& e) {
}
catch (SymbolNotFoundException& e) {
}
theLib.func1(1);
theLib.func2("aa"); // The function type is deduced with the args
// retType => int, args => const char* AND float
// So this calling is UNSAFE!
// You'd better explicitly specifiy the type of args like this
theLib.func4<int>(ASL_ARGS_T((const char*)"test", (float)2.3)); theLib.Unload(); *********************************************************************/ #ifndef ASL_INCLUDE_H
#define ASL_INCLUDE_H #ifdef WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif #include <cstdlib>
#include <exception>
#include <string> #if ASL_USE_CPP11
#include <functional>
#include <tuple>
#endif namespace ASL { namespace Private { template <class Head_, class Tail_>
struct TypeList
{
typedef Head_ Head;
typedef Tail_ Tail;
}; class NullType {}; template <int i_>
struct Int2Type
{
enum { value = i_ };
}; template <int condition_, class T0_, class T1_>
struct Select
{
typedef T0_ Result;
}; template <class T0_, class T1_>
struct Select<false, T0_, T1_>
{
typedef T1_ Result;
}; template <int condition_, int v0_, int v1_>
struct SelectInt
{
enum { value = v0_ };
}; template <int v0_, int v1_>
struct SelectInt<false, v0_, v1_>
{
enum { value = v1_ };
}; template <class Type_, int Ignore_>
struct MemberInfo
{
typedef Type_ Type;
enum {
ignore = Ignore_
};
}; template <class TList_, int startLine_, int endLine_, class ConcreteClass_>
struct CreateMemberIndicesImpl
{
typedef typename ConcreteClass_::template IsMemberPresent<endLine_> IsMemberPresent;
enum { isMemberPresent = IsMemberPresent::value }; typedef typename Select< isMemberPresent
, TypeList<MemberInfo<Int2Type<IsMemberPresent::index>, IsMemberPresent::ignoreError >, TList_>
, TList_ >::Result NewTList; typedef CreateMemberIndicesImpl<NewTList, startLine_, endLine_ - 1, ConcreteClass_> MemberIndicesImpl;
typedef typename MemberIndicesImpl::Indices Indices;
}; template <class TList_, int startLine_, class ConcreteClass_>
struct CreateMemberIndicesImpl<TList_, startLine_, startLine_, ConcreteClass_>
{
typedef TList_ Indices;
}; template <int startLine_, int endLine_, class ConcreteClass_>
struct CreateMemberIndices
{
typedef CreateMemberIndicesImpl< NullType, startLine_
, endLine_ - 1, ConcreteClass_ > MemberIndicesImpl;
typedef typename MemberIndicesImpl::Indices Indices;
}; template <class ConcreteClass_, int startLine_, int currentLine_>
struct GetMemberIndex
{
typedef typename ConcreteClass_::template IsMemberPresent<currentLine_> IsMemberPresent; enum {
index = SelectInt< IsMemberPresent::value
, IsMemberPresent::index
, GetMemberIndex<ConcreteClass_, startLine_, currentLine_ - 1>::index >::value + 1
};
}; template <class ConcreteClass_, int startLine_>
struct GetMemberIndex<ConcreteClass_, startLine_, startLine_>
{
enum { index = -1 };
}; #if ASL_USE_CPP11
typedef void* FuncType; // Pack of numbers.
// Nice idea, found at http://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer
template<int ...> struct Seq {}; // Metaprogramming Expansion
template<int N, int ...S> struct GenList : GenList < N - 1, N - 1, S... > {};
template<int ...S> struct GenList < 0, S... >
{
typedef Seq<S...> Result;
}; // Function that performs the actual call
template<typename Ret_, int ...S_, typename...Args_>
Ret_ ActualCall(Seq<S_...>, std::tuple<Args_...> tpl, const std::function<Ret_(Args_...)>& func)
{
// It calls the function while expanding the std::tuple to it's arguments via std::get<S>
return func(std::get<S_>(tpl) ...);
}
#endif
} class DefaultLibraryLoader
{
public:
typedef void* LibHandle; DefaultLibraryLoader()
{
lib_handle = NULL;
} template<class Char_>
bool Load(const Char_* name)
{
#if defined(WIN32)
lib_handle = LoadLibrary(name);
#else
lib_handle = dlopen(name, RTLD_LAZY);
#endif
return lib_handle != NULL;
} void Unload()
{
if (!IsLoaded()) {
return;
} #if defined(WIN32)
FreeLibrary((HMODULE)lib_handle);
#elif !defined(_ANDROID)
dlclose(lib_handle);
#endif lib_handle = NULL;
} template<class Char_>
void* LoadSymbol(const Char_* fun_name)
{
#if defined(WIN32)
return (void *)GetProcAddress((HMODULE)lib_handle, fun_name);
#elif !defined(_ANDROID)
return dlsym(lib_handle, fun_name);
#endif
} bool IsLoaded() const
{
return lib_handle != NULL;
} private:
LibHandle lib_handle;
}; class LibraryNotFoundException : public std::exception
{
public:
LibraryNotFoundException(const char* err)
{
_err = err;
} LibraryNotFoundException(const wchar_t* err)
{
static const size_t CONVERT_LEN = 256;
#if _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4996)
#endif
char mbsBuff[CONVERT_LEN + 1] = { 0 };
std::wcstombs(mbsBuff, err, CONVERT_LEN);
_err = mbsBuff;
#if _MSC_VER
#pragma warning(pop)
#endif
} ~LibraryNotFoundException() throw() {} virtual const char* what() const throw() {
return _err.c_str();
}
private:
std::string _err;
}; class SymbolNotFoundException : public std::exception
{
public:
SymbolNotFoundException(const char* err)
{
_err = err;
} SymbolNotFoundException(const wchar_t* err)
{
static const size_t CONVERT_LEN = 256;
#if _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4996)
#endif
char mbsBuff[CONVERT_LEN + 1] = { 0 };
std::wcstombs(mbsBuff, err, CONVERT_LEN);
_err = mbsBuff;
#if _MSC_VER
#pragma warning(pop)
#endif
} ~SymbolNotFoundException() throw() { } virtual const char* what() const throw() {
return _err.c_str();
} private:
std::string _err;
}; struct DefaultErrorHandler
{
template<class Char_>
static void OnLoadLibrary(const Char_* libName)
{
throw LibraryNotFoundException(libName);
} template<class Char_>
static void OnLoadSymbol(const Char_* symbolName, const bool ignore)
{
if (!ignore) {
throw SymbolNotFoundException(symbolName);
}
}
}; template < class ConcreteClass_,
class Loader_ = DefaultLibraryLoader,
class ErrorHandler_ = DefaultErrorHandler >
class AutoSharedLibrary
{
public:
AutoSharedLibrary()
{
} ~AutoSharedLibrary()
{
Unload();
} template<class Char_>
void Load(ConcreteClass_& object, const Char_* p)
{
if (!_loader.Load(p)) {
ErrorHandler_::OnLoadLibrary(p);
}
typedef typename ConcreteClass_::MemberIndices Indices;
LoadSymbols(object, Indices());
} void Unload()
{
_loader.Unload();
} private:
template <class Indices_>
void LoadSymbols(ConcreteClass_& object, Indices_ indices)
{
typedef typename Indices_::Head SymInfo;
typedef typename SymInfo::Type Index; bool ret = LoadSymbol(ConcreteClass_::getLoadName(Index()),
object.*ConcreteClass_::getMemberPtr(Index()));
if (!ret) {
ErrorHandler_::OnLoadSymbol(ConcreteClass_::getLoadName(Index()), (bool)SymInfo::ignore);
}
LoadSymbols(object, typename Indices_::Tail());
} void LoadSymbols(ConcreteClass_& object, Private::NullType indices)
{
} template <class FuncType_, class Char_>
bool LoadSymbol(const Char_* funcName, FuncType_& func)
{
func = (FuncType_)_loader.LoadSymbol(funcName);
return func != NULL;
} Loader_ _loader;
}; } #define ASL_LIBRARY_BEGIN(ConcreteClass_) \
ASL_LIBRARY_BEGIN_2(ConcreteClass_, ASL::DefaultLibraryLoader, ASL::DefaultErrorHandler) #define ASL_LIBRARY_BEGIN_2(ConcreteClass_, LibraryLoader_, ErrorHandler_) \
class ConcreteClass_ { \
private: \
typedef ConcreteClass_ ConcreteClass; \
enum { startLine = __LINE__ }; \
ASL::AutoSharedLibrary<ConcreteClass_, LibraryLoader_, ErrorHandler_> _libLoader; \
public: \
ConcreteClass_() { } \
\
~ConcreteClass_() { Unload(); } \
\
template<class Char_> void Load(const Char_* p) \
{ \
_libLoader.Load(*this, p); \
} \
void Unload() \
{ \
_libLoader.Unload(); \
} \
template <int lineNb_, class Dummy_ = ASL::Private::NullType> \
struct IsMemberPresent \
{ \
enum { value = false }; \
enum { index = 0 }; \
enum { ignoreError = false }; \
}; #define ASL_SYMBOL(DataType, name, loadName, ignoreNotFound) \
public: \
DataType name; \
private: \
typedef DataType ConcreteClass::* MemberPtr##name; \
public: \
template <class Dummy_> \
struct IsMemberPresent<__LINE__, Dummy_> \
{ \
enum { value = true }; \
enum { index = ASL::Private::GetMemberIndex< \
ConcreteClass, startLine, __LINE__ - 1>::index }; \
enum { ignoreError = ignoreNotFound}; \
}; \
static const char* getLoadName( \
ASL::Private::Int2Type<IsMemberPresent<__LINE__>::index >) \
{ return #loadName; } \
static MemberPtr##name getMemberPtr( \
ASL::Private::Int2Type< IsMemberPresent<__LINE__>::index >) \
{ return &ConcreteClass::name; } #if ASL_USE_CPP11 #define ASL_SYMBOL_T(name, loadName, ignoreNotFound) \
ASL_SYMBOL(ASL::Private::FuncType, name##_private_, loadName, ignoreNotFound) \
template<class Ret_, class... Args_> Ret_ name (std::tuple<Args_...> args) \
{ \
typedef Ret_(*FuncPointer)(Args_...); \
std::function<Ret_(Args_...)> func = reinterpret_cast<FuncPointer>(name##_private_); \
return ASL::Private::ActualCall(typename ASL::Private::GenList<sizeof...(Args_)>::Result(), args, func); \
} #define ASL_SYMBOL_EXPLICIT_T(name) \
ASL_SYMBOL_T(name, name, false) #define ASL_ARGS_T(...) (std::make_tuple<>(__VA_ARGS__)) #endif #define ASL_SYMBOL_DEFAULT(DataType, name, ignoreNotFound) \
ASL_SYMBOL(DataType, name, name, ignoreNotFound) #define ASL_SYMBOL_OPTIONAL(DataType, name) \
ASL_SYMBOL_DEFAULT(DataType, name, true) #define ASL_SYMBOL_EXPLICIT(DataType, name) \
ASL_SYMBOL_DEFAULT(DataType, name, false) #define ASL_LIBRARY_END() \
private: \
enum { endLine = __LINE__ }; \
public: \
typedef ASL::Private::CreateMemberIndices<startLine, endLine, ConcreteClass> \
::Indices MemberIndices; \
}; #endif

AutoSharedLibrary -- 基于模板元编程技术的跨平台C++动态链接载入库的更多相关文章

  1. c++ 模板元编程的一点体会

    趁着国庆长假快速翻了一遍传说中的.大名鼎鼎的 modern c++ design,钛合金狗眼顿时不保,已深深被其中各种模板奇技淫巧伤了身...论语言方面的深度,我看过的 c++ 书里大概只有 insi ...

  2. 读书笔记_Effective_C++_条款四十八:了解模板元编程

    作为模板部分的结束节,本条款谈到了模板元编程,元编程本质上就是将运行期的代价转移到编译期,它利用template编译生成C++源码,举下面阶乘例子: template <int N> st ...

  3. effective c++ Item 48 了解模板元编程

    1. TMP是什么? 模板元编程(template metaprogramming TMP)是实现基于模板的C++程序的过程,它能够在编译期执行.你可以想一想:一个模板元程序是用C++实现的并且可以在 ...

  4. 读书笔记 effective c++ Item 48 了解模板元编程

    1. TMP是什么? 模板元编程(template metaprogramming TMP)是实现基于模板的C++程序的过程,它能够在编译期执行.你可以想一想:一个模板元程序是用C++实现的并且可以在 ...

  5. C++模板元编程(C++ template metaprogramming)

    实验平台:Win7,VS2013 Community,GCC 4.8.3(在线版) 所谓元编程就是编写直接生成或操纵程序的程序,C++ 模板给 C++ 语言提供了元编程的能力,模板使 C++ 编程变得 ...

  6. C++模板元编程 - 函数重载决议选择工具(不知道起什么好名)完成

    这个还是基于之前实现的那个MultiState,为了实现三种类型“大类”的函数重载决议:所有整数.所有浮点数.字符串,分别将这三种“大类”的数据分配到对应的Converter上. 为此实现了一些方便的 ...

  7. C++模板元编程 - 3 逻辑结构,递归,一点列表的零碎,一点SFINAE

    本来想把scanr,foldr什么的都写了的,一想太麻烦了,就算了,模板元编程差不多也该结束了,离开学还有10天,之前几天部门还要纳新什么的,写不了几天代码了,所以赶紧把这个结束掉,明天继续抄轮子叔的 ...

  8. 简单的说一下:tarits技法就是一种模板元编程,起可以将本来处于运行期的事拉到编译期来做,增加了运行效率。 看以非模板元编程的例子,就是前面的那个例子:

    void adance(std::list<int>::iterator& iter, int d) { if(typeid(std::iterator_traits<std ...

  9. 现代c++与模板元编程

    最近在重温<c++程序设计新思维>这本经典著作,感慨颇多.由于成书较早,书中很多元编程的例子使用c++98实现的.而如今c++20即将带着concept,Ranges等新特性一同到来,不得 ...

随机推荐

  1. 截取字符(substr)检索字符位置(instr)

    1.SUBSTR(string,start_position,[length]) 求子字符串,返回字符串注释: string 元字符串start_position 开始位置(从0开始)length 可 ...

  2. PCB 后台自动系统集成与邮件推送实现

    在PCB行业中,工程系统是主要数据生产者,而这些数据不仅仅给自己系统使用呀,我们需要将数据传递到各系统,才达到各系统共同协作的目的. 这里以问答方式对实现方式进行讲解.呵呵呵! 后台自动集成问题解答: ...

  3. php 提交编辑数据没有变,返回0,判断

    php 提交编辑数据没有变,返回0,判断以TP为例子 $edit = D('Brand')->save($data);if($edit == true){ echo "修改成功&quo ...

  4. BZOJ 1511 KMP

    题意:求出每个前缀的最长周期之和(等于本身的算0) 思路: 求出来next数组  建出next树 找到不为0的最小的 n减去它就是答案 //By SiriusRen #include <cstd ...

  5. 【java基础】(6)内部类

    内部类不是很好理解,但说白了其实也就是一个类中还包含着另外一个类 如同一个人是由大脑.肢体.器官等身体结果组成,而内部类相当于其中的某个器官之一,例如心脏:它也有自己的属性和行为(血液.跳动) 显然, ...

  6. Android使用charles抓包

    1.下载并安状软件,官网在此: 2.前题条件,电脑和手机必须在同一网段 3.在Charles界面选择菜单 proxy->proxy settings 勾选"Enable transpa ...

  7. OpenCV边缘检测的详细参数调节

    1. findCountours 转载于http://blog.sina.com.cn/s/blog_7155fb1a0101a90h.html findContours函数,这个函数的原型为: &l ...

  8. 【sicily】 1934. 移动小球

    Description 你有一些小球,从左到右依次编号为1,2,3,...,n. 你可以执行两种指令(1或者2).其中, 1 X Y表示把小球X移动到小球Y的左边, 2 X Y表示把小球X移动到小球Y ...

  9. js判断数组中是否包含某个值

    /** * 判断数组中是否包含某个值 * @param arr 数组 * @param str 值 * @returns {boolean} */ function contains(arr, str ...

  10. openstack--memecache

    一.缓存系统 静态web页面: 1.工作流程: 在静态Web程序中,客户端使用Web浏览器(IE.FireFox等)经过网络(Network)连接到服务器上,使用HTTP协议发起一个请求(Reques ...