泛型单例存在的问题:
泛型单例要能够创建所有的类型对象,但是这些类型的构造函数形参不尽相同,参数个数和参数类型可能都不相同,导致我们不容易做一个所有类型都通用的单例。
c++11借助可变参数模板实现单例(上代码)
#include <iostream>
using namespace std;
template <typename T>
class Singleton
{
public:
template<typename... Args> //可变参数模板
static T* Instance(Args&&... args)
{
if (m_pInstance == nullptr)
m_pInstance = new T(std::forward<Args>(args)...); //完美转发
return m_pInstance;
}
static T* GetInstance()
{
if (m_pInstance == nullptr)
throw std::logic_error("Init error");
return m_pInstance;
}
//销毁
static void DestroyInstance()
{
delete m_pInstance;
m_pInstance = nullptr;
}
private:
Singleton(void);
virtual ~Singleton(void);
Singleton(const Singleton&);
Singleton& oprator = (const Singleton&); //拷贝构造函数
private:
static T* m_pInstance;
};
template <class T> T* Singleton<T>::m_pInstance = nullptr;
struct func1
{
func1(const string&)
{
cout << "l" << endl;
}
func1(string&& x)
{
cout << "r" << endl;
}
};
struct func2
{
func2(const string&)
{
cout << "l" << endl;
}
func2(string&& x)
{
cout << "r" << endl;
}
};
struct func3
{
func3(int m, float x) {}
void fun()
{
cout << "func3" << endl;
}
};
int main()
{
string str = "test";
Singleton<func1>::Instance(str);
//move之后str变为右值,避免复制(右值引用的移动语义提高性能)
Singleton<func2>::Instance(std::move(str));
Singleton<func3>::Instance(1, 1.2);
Singleton<func3>::Instance()->fun();
//释放单例
Singleton<func1>::DestroyInstance();
Singleton<func2>::DestroyInstance();
Singleton<func3>::DestroyInstance();
system("pause");
return 0;
}
c++11的可变参数模板消除了重复的可变参数的定义,避免重复的代码累加,同时支持完美转发,既避免了不必要的内存复制,无论是左值还是右值都能转发到正确的构造函数中,又增加了灵活性。
补充:
完美转发: 在函数模板中,完全依照模板的参数的类型(即保持函数的左值、右值特征),将参数传递给函数模板中调用的另一个函数。c++11中提供了std::forward实现完美转发。
右值引用、完美转发结合可变参数模板,可以实现一个万能的函数包装器
template <class Function, class... Args>
inline auto FuncWrapper(Function && f, Args && ... args) -> decltype(f(std::forward<Args>...))
{
return f(std::forward<Args>(args)...);
}