c++11 之可变参数模板

目的:包含0到任意个模板参数

声明可变参数模板需要在typename或class 后面加上省略号“...”

一、可变参数模板函数

template

void f(T...args)

{

 cout<

}


可变参数展开有两种方式:

1.通过递归的模板函数来将参数展开

2.通过逗号表达式和初始化列表方式展开参数包

对于1介绍一种通过type_traits来展开并打印参数包,为什么选用这个,因为很难,你看不懂?????

template

typename std::enable_if::value>::type printtp(Tuple t)

{

 }

template

typename std::enable_if::value>::type printtp(Tuple t)

{

 std::cout<(t)<

 printtp(t);

}

template

void print(Args...args)

{

 printtp(std::make_tuple(args...));

}

什么玩意!!!!!!!!!!!!!!!

(2)逗号和初始化列表展开参数列表

template

void peintarg(T t)

{

 cout<< t<

}

template< class ...Args>

void expand(Args...args)

{

 int arr[] = { (printage(args), 0)...};

}

expand(1,2,3,4);

这里是通过一个初始化列表来初始化一个变长数组,{(printarg(args),0)...}展开为((printarg(arg1),0)、((printarg2),0).....

int数组的目的就是为了在数组构造的过程展开参数包

改进,使用initializer_list来替代原来的int arr[]数组

template

void expand(Args...args)

{

 std::initializer_list{(printarg(args),0)...};

}

再改进,用lambda表达式:

template

void expand(Args...args)

{

 std::initializer_list{([&]{cout<

}

二、可变参数模板类

1.模板递归和特化方式展开参数包

2.继承方式

啊啊啊,不想看了,感觉和函数的没两样,暂时不看了吧!!!


三、可变参数消除重复代码

template

T* Instance(Args...args)

{

  return new T(args...);

}

在上面中,Args是值拷贝的,存在性能损耗,可以通过完美转发来消除损耗

template

T* Instance(Args&&...args)

{

 return new T(std::forward(args)...); //完美转发这个玩意好啊

}

三、可变参数模板和type_traits的综合应用

1.optional

未被初始化的optional对象是无效值。

这个是c++14才支持的,这里可以进行手动实现

#include

template

class Optional

{

 using data_t = typename std::aligned_storage::value>::type;

 public:

  Optional() {};

  Optional(const T& v)

  {

    Create(v);

  }

 Optional(const Optional& other)

 {

  if(other.IsInit())

   Assign(other);

}

~Optional()

 {

    Destroy();

 }

template

void Emplace(Args&& ...args)

{

 Destroy();

 Create(std::forward(args)...);

}

bool IsInit() const { return m_hasInit;}

 explicit operator bool() const   // 这个bool符号重载,使用:if(xxx)来表示

{

  return IsInit();

}

T const& operator*() const

{

  if(IsInit())

 {
   return *((T*)(&m_data));

  }

  throw std::logic_error("is not init");

}

private:

 template

void Create(Args&& ...args)

{
  new (&m_data) T(std::forward(args)...);

  m_hasInit = true;

}

void Destroy()

{

 if(m_hasInit)

 {

  m_hasInit = false;

  ((T*)(&m_data))->~T();

 }

}

void Assign(const Option& other)

{

  if(other.IsInit())

{

  Copy(other.m_data);

  m_hasInit = true;

}
else

{

 Destroy();

}

}

void Copy(const data_t& val)

{

 Destroy();

 new (&m_data) T(*((T*)(&val)));

}

private:

  bool m_hasInit = false;

  data_t m_data;

};

2.惰性求值

类似桥接模式,是在创建对象,调用成员函数才是真正的求值

下面再举个例子,这个例子真的很吊的:

#include

template

struct Lazy

{

    Lazy(){};

template

// 保存函数

Lazy(Func& f, Args&&...args)

{
m_func = [&f, &args..]{return f(args...);};

}

T& Value()

{

if(!m_value.IsInit())

{

m_value = m_func();

}

return *m_value;

}

bool IsVauleCreated() const

{

return m_value.IsInit();

}

private:

std::function m_func;

Optinal m_value;

};

template

Lazy::type> lazy(Func&& func, Args&&...args)

{

  return Lazy::type>(std::forward(fun), std::forward(args)...); //这句调用 的就是上面的保存函数

}

上面一个函数是重要的函数,主要是为了更加方便地使用Lazy,调用其构造函数:

int Foo(int x)

{

 return x*2;

}

int y =4;

auto lazyer = lazy(Foo, y);

cout<

std::function用来保存输入的函数,这个定义是没有参数的,因为可以通过一个lambda表达式去初始化一个function,而lambda表达式可以捕获参数,无需定义function的参数

还可以通过bind绑定来将N元的入参函数变为std::function

m_func = std::bind(f, std::forward(args)...);

如果含有占位符,则需要写参数:

std::function f = std::bind(&HT, std::placeholders::_1);


你可能感兴趣的:(c++11,模板,可变参数)