递归 enable_if 和类型转换
Recursive enable_if and type transform
我想从 typename U
到 typename T
添加相同数字的指针,例如当 T = int***
和 U = int*
时,结果是 int****
.所以,我写下:
#include <type_traits>
template <typename T, typename U,
typename std::enable_if_t<std::is_pointer<U>::value>* = nullptr>
auto addPointer(T, U)
-> decltype(addPointer(std::declval<std::add_pointer_t<T>>(),
std::declval<std::remove_pointer_t<U>>()));
template <typename T, typename U,
typename std::enable_if_t<!std::is_pointer<U>::value>* = nullptr>
auto addPointer(T, U) -> T;
int main()
{
using t =
decltype(addPointer(std::declval<int***>(), std::declval<int*>()));
}
我在 Linux clang 3.7 上得到以下信息:
$ clang++ -std=c++14 -stdlib=libc++ -lc++abi -Wall -Wextra a.cpp
a.cpp:16:18: error: no matching function for call to 'addPointer'
decltype(addPointer(std::declval<int***>(), std::declval<int*>()));
^~~~~~~~~~
a.cpp:5:6: note: candidate template ignored: substitution failure [with T = int ***, U =
int *, = nullptr]: call to function 'addPointer' that is neither visible in the
template definition nor found by argument-dependent lookup
auto addPointer(T, U)
^
/usr/bin/../include/c++/v1/type_traits:244:78: note: candidate template ignored: disabled
by 'enable_if' [with T = int ***, U = int *]
...<bool _Bp, class _Tp = void> using enable_if_t = typename enable_if<_Bp, _Tp>::type;
^
1 error generated.
为什么我会收到错误消息?
这里不需要使用整个 SFINAE,您可以通过简单的模板专业化更轻松地实现这一点:
template <typename T, typename U>
struct addPointer
{
typedef T type;
};
template <typename T, typename U>
struct addPointer<T,U*>
{
typedef typename addPointer<T*,U>::type type;
};
int main()
{
using t = addPointer<int***, int*>::type;
}
如果您绝对想使用 enable_if
和函数而不是 traits-struct,则以下方法可行:
#include <type_traits>
template <typename T, typename U,
typename K = std::enable_if_t<!std::is_pointer<U>::value>>
auto addPointer(T, U) -> T;
template <typename T, typename U,
typename K = std::enable_if_t<std::is_pointer<U>::value>>
auto addPointer(T, U)
-> decltype(addPointer(std::declval<std::add_pointer_t<T>>(),
std::declval<std::remove_pointer_t<U>>()));
int main()
{
using t =
decltype(addPointer(std::declval<int***>(), std::declval<int*>()));
}
当我们处理标量时,ADL 不会在全局命名空间中查找。这样不仅无法找到后备重载,而且您当前定义的重载也无法在 trailing-return-type.
中引用
对于 C++14,您的问题有更好的解决方案,可以绕过该问题:
template <typename T>
T addPointer(T, ...);
template <typename T, typename U>
auto addPointer(T t, U* u) {return addPointer(&t, *u);}
Demo.
我想从 typename U
到 typename T
添加相同数字的指针,例如当 T = int***
和 U = int*
时,结果是 int****
.所以,我写下:
#include <type_traits>
template <typename T, typename U,
typename std::enable_if_t<std::is_pointer<U>::value>* = nullptr>
auto addPointer(T, U)
-> decltype(addPointer(std::declval<std::add_pointer_t<T>>(),
std::declval<std::remove_pointer_t<U>>()));
template <typename T, typename U,
typename std::enable_if_t<!std::is_pointer<U>::value>* = nullptr>
auto addPointer(T, U) -> T;
int main()
{
using t =
decltype(addPointer(std::declval<int***>(), std::declval<int*>()));
}
我在 Linux clang 3.7 上得到以下信息:
$ clang++ -std=c++14 -stdlib=libc++ -lc++abi -Wall -Wextra a.cpp
a.cpp:16:18: error: no matching function for call to 'addPointer'
decltype(addPointer(std::declval<int***>(), std::declval<int*>()));
^~~~~~~~~~
a.cpp:5:6: note: candidate template ignored: substitution failure [with T = int ***, U =
int *, = nullptr]: call to function 'addPointer' that is neither visible in the
template definition nor found by argument-dependent lookup
auto addPointer(T, U)
^
/usr/bin/../include/c++/v1/type_traits:244:78: note: candidate template ignored: disabled
by 'enable_if' [with T = int ***, U = int *]
...<bool _Bp, class _Tp = void> using enable_if_t = typename enable_if<_Bp, _Tp>::type;
^
1 error generated.
为什么我会收到错误消息?
这里不需要使用整个 SFINAE,您可以通过简单的模板专业化更轻松地实现这一点:
template <typename T, typename U>
struct addPointer
{
typedef T type;
};
template <typename T, typename U>
struct addPointer<T,U*>
{
typedef typename addPointer<T*,U>::type type;
};
int main()
{
using t = addPointer<int***, int*>::type;
}
如果您绝对想使用 enable_if
和函数而不是 traits-struct,则以下方法可行:
#include <type_traits>
template <typename T, typename U,
typename K = std::enable_if_t<!std::is_pointer<U>::value>>
auto addPointer(T, U) -> T;
template <typename T, typename U,
typename K = std::enable_if_t<std::is_pointer<U>::value>>
auto addPointer(T, U)
-> decltype(addPointer(std::declval<std::add_pointer_t<T>>(),
std::declval<std::remove_pointer_t<U>>()));
int main()
{
using t =
decltype(addPointer(std::declval<int***>(), std::declval<int*>()));
}
当我们处理标量时,ADL 不会在全局命名空间中查找。这样不仅无法找到后备重载,而且您当前定义的重载也无法在 trailing-return-type.
中引用对于 C++14,您的问题有更好的解决方案,可以绕过该问题:
template <typename T>
T addPointer(T, ...);
template <typename T, typename U>
auto addPointer(T t, U* u) {return addPointer(&t, *u);}
Demo.