【问题标题】:Get pointer level from type rather than from variable从类型而不是从变量获取指针级别
【发布时间】:2016-09-01 19:28:27
【问题描述】:

我尝试将指针深度显示为整数个星号 - 例如 int*** 将是 3。但是我没有从类型计算它,而是编写了要求每个级别的指针都必须正确初始化的代码。这是我尝试过的:

#include <iostream>
#include <utility>

// no pointers involved
template <class T>
std::size_t get_pointer_level(T)
{
    return 0;
}

// final value reached, returning depth
template <class T>
std::size_t get_pointer_level(std::pair<std::size_t, T> arg)
{
    return arg.first;
}

// function that accummulates depth
template <class T>
auto get_pointer_level(std::pair<std::size_t, T*> arg)
{
    return get_pointer_level(std::make_pair(arg.first+1, *arg.second));
}

// initial function called for pointer argument
template <class T>
auto get_pointer_level(T* arg)
{
    return get_pointer_level(std::make_pair(std::size_t(1), *arg));
}


int main(void)
{
    int a = 10;
    auto b = &a; //int*
    auto c = &b; //int**
    auto d = &c; //int***
    auto e = &d; //int****
    std::cout << get_pointer_level(e) << std::endl; //4
}

我很确定它很可能仅与类型一起工作。我想语法会是这样的:

get_pointer_level<int****>::value

有什么想法吗?


编辑: 感谢您的解决方案!这是我想要完成的最终功能:

template <std::size_t A, std::size_t B>
struct is_smaller
{
    enum {value = (A < B)? 1 : 0};
};
template<std::size_t Target, typename T, std::size_t Actual = get_pointer_level<T>::value>
T value_at_level(T pointer)
{
    static_assert(Actual==Target, "Invalid target level!");
    return pointer;
}

template<std::size_t Target, typename T, std::size_t Actual = get_pointer_level<T*>::value,
         typename = std::enable_if<is_smaller<Target, Actual>::value>::type>
auto value_at_level(T* pointer)
{
    return value_at_level<Target>(*pointer);
}

int main()
{
    int a = 5;
    auto b = &a; //int*
    auto c = &b; //int**
    auto d = &c; //int***
    auto e = &d; //int****

    std::cout << "int from int****: " << value_at_level<0>(e) << std::endl; //ok
    std::cout << "int* from int***: " << value_at_level<1>(d) << std::endl; //ok
    std::cout << "int** from int**: " << value_at_level<2>(c) << std::endl; //ok
    std::cout << "int*** from int*: " << value_at_level<3>(b) << std::endl; //error
    std::cout << "int**** from int: " << value_at_level<5>(a) << std::endl; //error
}

【问题讨论】:

  • 好奇:建议的用例是什么?
  • 这似乎是一个微不足道的 TMP;为什么这么复杂?
  • 我想要实现的是能够在给定级别取消引用指针。需要所需的整数值来检查需要取消引用的次数。示例:我想从int***** 值中获取int* 值。整数将是 15,因此所需的取消引用量将是 4 次。

标签: c++ templates pointers


【解决方案1】:

部分专业化练习:

#include <cstddef>

template<typename T, std::size_t S>
struct get_pointer_level_impl
{
    static const std::size_t value = S;
};

template<typename T, std::size_t S>
struct get_pointer_level_impl<T*, S> : get_pointer_level_impl<T, S+1>
{

};

template<typename T>
struct get_pointer_level : get_pointer_level_impl<T, 0>
{

};

#include <iostream>

int main()
{
    std::cout << get_pointer_level<int>::value << "\n";
    std::cout << get_pointer_level<int*>::value << "\n";
    std::cout << get_pointer_level<int**>::value << "\n";
    std::cout << get_pointer_level<int***>::value << "\n";
}

输出:

0
1
2
3

【讨论】:

    【解决方案2】:

    如果您可以将其称为get_pointer_level&lt;int*&gt;() 而不是get_pointer_level&lt;int*&gt;::value,那么递归constexpr 函数就可以正常工作:

    #include <iostream>
    #include <type_traits>
    
    template <typename T>
    constexpr int get_pointer_level()
    {
        return !std::is_pointer<T>::value ? 0 : 1 + get_pointer_level<typename std::remove_pointer<T>::type>();
    }
    
    int main() {
        std::cout << get_pointer_level<int>() << '\n';
        std::cout << get_pointer_level<int*>() << '\n';
        std::cout << get_pointer_level<int**>() << '\n';
        std::cout << get_pointer_level<int***>() << '\n';
        std::cout << get_pointer_level<int****>() << '\n';
    }
    

    LIVE DEMO

    【讨论】:

      【解决方案3】:

      使用帮助类来确定指针级别。

      #include <iostream>
      
      template <class T> struct PointerLevel
      {
         static const std::size_t value = 0;
      };
      
      template <class T> struct PointerLevel<T*>
      {
         static const std::size_t value = PointerLevel<T>::value + 1;
      };
      
      // no pointers involved
      template <class T>
      std::size_t get_pointer_level(T)
      {
         return PointerLevel<T>::value;
      }
      
      int main(void)
      {
         int a = 10;
         auto b = &a; //int*
         auto c = &b; //int**
         auto d = &c; //int***
         auto e = &d; //int****
         std::cout << get_pointer_level(a) << std::endl;
         std::cout << get_pointer_level(b) << std::endl;
         std::cout << get_pointer_level(c) << std::endl;
         std::cout << get_pointer_level(d) << std::endl;
         std::cout << get_pointer_level(e) << std::endl; //4
      }
      

      输出:

      0
      1
      2
      3
      4
      

      【讨论】:

        【解决方案4】:

        你觉得使用 typeid(your type).name() 怎么样??

        std::string s( typeid(int***).name()); 
        size_t n = std::count(s.begin(), s.end(), "*");
        

        【讨论】:

        • 错位名称不能使用'*' 字符可以吗?
        • 不考虑不可移植,它不是一个编译时解决方案,即使假设名称未损坏,它也只适用于简单类型(std::vector&lt;T*&gt;* 会返回什么?)
        • 对不起,我的错误,我发现“但是,您永远不应该依赖确切的内容,例如 std::type_info::name() 返回的内容,因为这是特定于实现的编译。”
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-02-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-08
        • 1970-01-01
        相关资源
        最近更新 更多