我目前有以下功能:
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);
i
为int
,t
为char*
,f
为double
。
如果我想传递一个空指针,那么这个例外很有效。
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
?
答案 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_t
,all_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
放在你的变量体之前。
专门化模板功能很少 - 只需覆盖。