【问题标题】:Recursive enable_if and type transform递归 enable_if 和类型转换
【发布时间】:2016-03-08 09:24:23
【问题描述】:

我想在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.

为什么我会收到错误消息?

【问题讨论】:

  • auto addPointer(T, U) -&gt; T; 版本移到另一个重载之前
  • 使用这么多级别的间接是code smell
  • @PiotrSkotnicki U = int* 有效,但 U = int** 导致同样的错误...
  • 只是出于好奇:您曾经可以用它做什么? :-)
  • @matz 我的 TMP 练习库 :)

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


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    这里不需要使用整个 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 和函数而不是特征结构,则以下方法可行:

    #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*>()));
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多