将nullptr传递给可变参数模板指针

时间:2014-08-19 14:57:51

标签: c++ c++11 variadic-templates

我目前有以下功能:

template <typename T, typename... Args> void Get(T* out, Args*... other);
template <typename T> void Get(T* out);
template <> void Get<int>(int* out);
template <> void Get<int64>(int64* out);
template <> void Get<double>(double* out);
template <> void Get<char*>(char** out);
template <> void Get<void*>(void** out);

使用:

调用
Get(&i, &t, &f);

iinttchar*fdouble

如果我想传递一个空指针,那么这个例外很有效。

Get(&i, nullptr, nullptr, &t, &f);

给出

main.cpp: In function ‘int main()’:
main.cpp:94:39: error: no matching function for call to ‘Get(int*, std::nullptr_t, std::nullptr_t, char**, float*)’
  Get(&i, nullptr, nullptr, &txt, &f);
                                       ^
main.cpp:94:39: note: candidates are:
main.cpp:18:46: note: template<class T, class ... Args> void Get(T*, Args* ...)
 template <typename T, typename... Args> void Get(T* out, Args*... other)
                                              ^
main.cpp:18:46: note:   template argument deduction/substitution failed:
main.cpp:94:39: note:   mismatched types ‘Args*’ and ‘std::nullptr_t’
  Get(&i, nullptr, nullptr, &txt, &f);
                                       ^
main.cpp:28:28: note: template<class T> void Get(T*)
 template <typename T> void Get(T* out)
                            ^
main.cpp:28:28: note:   template argument deduction/substitution failed:
main.cpp:94:39: note:   candidate expects 1 argument, 5 provided
  Get(&i, nullptr, nullptr, &txt, &f);
                                       ^

如何重写我的Get函数以保留旧用法,但他们也会接受nullptr

2 个答案:

答案 0 :(得分:2)

您可以执行以下操作:

template <typename T, typename... Args>
typename std::enable_if<std::is_same<std::nullptr_t, T>::value || std::is_pointer<T>::value>::type
Get(T out, Args... other);

template <typename T>
typename std::enable_if<std::is_same<std::nullptr_t, T>::value || std::is_pointer<T>::value>::type
Get(T out);

所以你的专业化是不同的:

template <> void Get<int*>(int* out);
template <> void Get<int64*>(int64* out);
template <> void Get<double*>(double* out);
template <> void Get<char**>(char** out);
template <> void Get<void**>(void** out);

并可能:

template <> void Get<nullptr_t>(nullptr_t); // the new one

BTW,您可能更喜欢重载(对于Get只有一个参数):Live example

答案 1 :(得分:0)

首先,一些元编程样板。这定义了enable_if_tall_of

template<bool B, class T=void>
using enable_if_t=typename std::enable_if<B,T>::type;
namespace details {

  template <template<class>class test, class=void, class... Ts>
  struct all_of : std::true_type {};
  template <template<class>class test, class T0, class... Ts>
  struct all_of<test, enable_if_t< !test<T0>::value >, Ts... > : std::false_type {};
  template <template<class>class test, class T0, class... Ts>
  struct all_of<test, enable_if_t< test<T0>::value >, Ts... > : all_of<test, void, Ts...> {};
}
template<template<class>class test, class... Ts>
struct all_of : details::all_of<test, void, Ts...> {};

这两者通常都很有用。 enable_if_t std是{+ 1}}中的C ++ 11内容,如果您完全支持,请改用std::enable_if_t

接下来,检测某些东西是指针还是nullptr的特征:

template<class X>
struct is_ptr : std::false_type {};
template<class X>
struct is_ptr<X*> : std::true_type {};
template<>
struct is_ptr<std::nullptr_t> : std::true_type {};

然后我们使用该特征为我们的Get多方法提供SFINAE保护:

template <typename T, typename... Args>
enable_if_t<all_of<is_ptr, T, Args...>> Get(T const& out, Args const&... other);

接下来,关于功能模板专业化的有趣之处是&#34;你没有做到这一点&#34;并且&#34;你不应该这样做&#34;。您实际上正在超载Get<T,Args...>,您只是专注于Get<T>。如果你使用演绎,那就没什么意义了:

void Get( std::nullptr_t out );
void Get( int* out );
void Get( int64* out );
void Get( double* out );
void Get( char** out );
void Get( void** out );

如果变量主体进行递归,则将这些单{arg}版本的Get放在你的变量体之前。

专门化模板功能很少 - 只需覆盖。