c++ - 递归取消引用指针

标签 c++ templates pointers c++11 enable-if

在尝试在这里回答一个问题时,我发现了这个问题:

How to recursively dereference pointer (C++03)?

根据答案改编的代码如下:

template<typename T> T& dereference(T &v) { return v; }

template<typename T> const T& dereference(const T &v) { return v; }


template <typename T>
typename std::enable_if<!std::is_pointer<T>::value, T&>::type
dereference(T *v) {
     return dereference(*v);
}

但是,在这个测试中,它无法将指针到指针取消引用到值类型:

template <typename T>
class A
{
public:
         bool compare(T a, T b){
                return dereference(a) < dereference(b);
        }


};

int main()
{

        int u = 10;
        int *v = &u;
        int **w = &v;

        int i = 5;
        int *j = &i;
        int **k = &j;

        A<int> a;
        A<int*> b;
        A<int**> c;


        std::cout << a.compare(i, u) << std::endl;
        std::cout << b.compare(j, v) << std::endl;


        // This fails - 5 < 10 == 0
        std::cout << **k << " < " <<  **w <<  " == " << c.compare(k, w) << std::endl;


        return 0;

}

显然,wk只取消引用一次,这会导致 operator<在两个指针上调用。

我可以通过添加以下内容来解决这个问题:

template <typename T>
typename std::enable_if<!std::is_pointer<T>::value, T&>::type
dereference(T **v) {
     return dereference(*v);
}

但随后它将因 int*** 而失败.

有没有什么方法可以在不手动添加关卡的情况下递归执行此操作?

注意这只是“理论”问题。

最佳答案

这可以通过使用自定义 can_dereference 特征来实现:

template <typename T>
struct can_dereference_helper {
    template <typename U, typename = decltype(*std::declval<U>())>
    static std::true_type test(U);
    template <typename...U>
    static std::false_type test(U...);
    using type = decltype(test(std::declval<T>()));
};

template <typename T>
struct can_dereference :
  can_dereference_helper<typename std::decay<T>::type>::type {};

和一些带有 bit'o 标签调度的相互递归函数:

template <typename T>
auto recursive_dereference(T&& t, std::false_type) ->
  decltype(std::forward<T>(t)) {
    return std::forward<T>(t);
}

template <typename T>
auto recursive_dereference(T&& t) ->
  decltype(recursive_dereference(std::forward<T>(t), can_dereference<T>{}));

template <typename T>
auto recursive_dereference(T&& t, std::true_type) ->
  decltype(recursive_dereference(*std::forward<T>(t))) {
    return recursive_dereference(*std::forward<T>(t));
}

template <typename T>
auto recursive_dereference(T&& t) ->
  decltype(recursive_dereference(std::forward<T>(t), can_dereference<T>{})) {
    return recursive_dereference(std::forward<T>(t), can_dereference<T>{});
}

See it work live at Coliru.与 Kerrek 的回答相比,这似乎有点矫枉过正,但我​​采用了一种通用方法,该方法将取消引用任何支持 operator* 的内容。我会让您决定哪种工具最适合您的问题。

关于c++ - 递归取消引用指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20222059/

相关文章:

c - C中的全局文件指针声明

c - 在 C 中使用双指针查询

c++ - 如何消除这种与继承相关的代码异味?

c++ - 函数模板特化类型——它是可选的吗?

c - 多维数组 : don't the pointers point to their own addresses?

c++ - 重载运算符的模板 : error: overloaded 'operator*' must have at least one parameter of class or enumeration type

c++ - 在嵌套的 lambda 中应用 function_traits 时编译失败

c++ - boost spirit : Difference between operators "%=" and "="

c++ - 以 clang 格式对齐函数声明

c++ - 连接到 C 中的主机