创建可变参数仅接受引用或指针

Dan*_*ani 5 c++ variadic-templates c++11 template-argument-deduction

我可以创建一个只接受指针的可变参数模板:

template<typename ... Types>
void F(Types *... args);
Run Code Online (Sandbox Code Playgroud)

或者只接受引用的可变参数模板:

template<typename ... Types>
void F(Types &... args);
Run Code Online (Sandbox Code Playgroud)

如何创建一个接受非const引用或指针的模板?
例如

int a, b, c;
F(a, &b); // => F<int &, int *>
F(a, 3); // Error, 3 not pointer and cannot bind to non const-reference
Run Code Online (Sandbox Code Playgroud)

注意:参考版本可能看起来没问题,因为它可以绑定到指针引用但不是因为它不会绑定到 int * const

Tar*_*ama 6

我们可以编写一个特征来检查类型是指针还是非const引用:

template <typename T>
using is_pointer_or_ref = 
  std::integral_constant<bool, std::is_pointer<T>::value || 
     (std::is_lvalue_reference<T>::value && 
     !std::is_const<typename std::remove_reference<T>::type>::value)>;
Run Code Online (Sandbox Code Playgroud)

然后我们可以使用Jonathan Wakelyand_编写一个特征来检查参数包:

template<typename... Conds>
  struct and_
  : std::true_type
  { };

template<typename Cond, typename... Conds>
  struct and_<Cond, Conds...>
  : std::conditional<Cond::value, and_<Conds...>, std::false_type>::type
  { };

template <typename... Ts>
using are_pointer_or_ref = and_<is_pointer_or_ref<Ts>...>;
Run Code Online (Sandbox Code Playgroud)

现在我们可以std::enable_if用来验证类型:

template<typename ... Types, 
   typename std::enable_if<are_pointer_or_ref<Types...>::value>::type* = nullptr>
void F(Types&&... args){}
Run Code Online (Sandbox Code Playgroud)

请注意,转发引用是检测参数的值类别以使引用检查正常工作所必需的.

Live Demo