递归enable_if和类型转换

时间:2015-12-03 16:42:28

标签: c++ metaprogramming c++14 template-meta-programming sfinae

我想在typename Utypename 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 *, $2 = 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.

为什么我会收到错误?

2 个答案:

答案 0 :(得分:2)

当我们处理标量时,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

答案 1 :(得分:0)

此处无需使用整个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*>()));
}