存储或反射变量的"reference level"

Store or reflect on the "reference level" of a variable

本文关键字:reference level 变量 反射 存储      更新时间:2023-10-16

C++中是否有一种方法可以反映变量的"指针级别数"(例如,int* a是1级,int** b是2级,而int c是0级)

除了使用typeid并解析由此产生的字符串之外?

我之所以这么问,是因为我正在使用指向成员函数的指针,并且我需要知道在编译时是将成员函数调用为obj->func()还是obj.func()

如果objT**,则执行obj.*foo是不正确的。所以你只需要弄清楚它是指针还是非指针。您可以为此使用重载。

template<typename T, typename M> void f(T *obj, M m) { // pointer
  (obj->*m)();
}
template<typename T, typename M> void f(T &obj, M m) { // not a pointer
  (obj.*m)();
}

它的缺点是,它只适用于零参数成员函数指针,并且不会返回这些函数返回的值(如果有的话)。您不能执行以下操作(可以很容易地实现),因为两个分支都将进行类型检查

if(is_pointer(obj)) v = (obj->*m)(arg...); else v = (obj.*m)(args...);

如果对象是指针,那么可以只调用一个函数来取消引用对象

template<typename T> T &deref(T *t) { return *t; }
template<typename T> T &deref(T &t) { return t; }

然后你可以说

v = (deref(obj).*m)(args...);

您可以从TR1中的type_traits标头中使用std::is_pointer(它使用部分专用化来生成答案),但只使用重载解析可能更简单。

这里有一个例子,假设返回无效,没有参数,并且不需要处理多个间接级别:

template <typename T, typename F>
inline void invoke(T& obj, F func)
{
    (obj.*func)();
}
template <typename T, typename F>
inline void invoke(T* obj, F func)
{
    (obj->*func)();
}

如果您需要处理多个级别的间接,您可以将第二个函数替换为:

template <typename T, typename F>
inline void invoke(T* obj, F func)
{
    invoke(*obj, func);
}

这将递归地剥离间接级别,直到您最终得到可以在上调用成员函数的东西。

部分模板专业化将很容易告诉您:

template<typename T>
struct PtrLevel
{
    enum { value = 0 };
};
template<typename TTarget>
struct PtrLevel<TTarget*>
{
    enum { value = PtrLevel<TTarget>::value + 1 };
};

演示:http://ideone.com/ZPH8X

在C++0x中,您可能会使用decltype和SFINAE来处理智能指针,这样它们就会被报告为具有非零指针级别。

一点模板魔术拯救:

template<typename T>
struct Depth { enum DepthEnum { value = 0 };};
template<typename T>
struct Depth<T*> { enum DepthEnum{ value = Depth<T>::value +1 };};
template<typename T>
size_t getDepth(T const& o)
{
    return Depth<T>::value;
}
int main()
{
    int         a0;
    int*        a1;
    int**       a2;
    int***      a3;
    int****     a4;
    int*****    a5;
    int******   a6;
    std::cout << getDepth(a0) << std::endl;
    std::cout << getDepth(a1) << std::endl;
    std::cout << getDepth(a2) << std::endl;
    std::cout << getDepth(a3) << std::endl;
    std::cout << getDepth(a4) << std::endl;
    std::cout << getDepth(a5) << std::endl;
    std::cout << getDepth(a6) << std::endl;
}

输出:

> g++ test.cpp
> ./a.out
0
1
2
3
4
5
6

回到你想要它的原因。这似乎有点可疑。您的编译器已经知道在编译时要使用哪个版本。请记住,C++对其类型非常严格,并且这些信息在编译时是已知的,因此如果您使用了错误的版本,则会出现编译器错误。

我不知道有任何内置的方法可以做到这一点,但你可以实现一个模拟"计数指针"的小模板类,这样你就可以很容易地确定你的"指针深度":

template <typename T> class Ptr {
  private:
    T* ptr;
    int d;
  public:
    // overload all meaningful operators, like * etc.
    // e.g.
    T& operator*() {
      return *T;
    }
    int depth() const {
      return d;
    }
}

只要你的指针是有效的,你就可以使用以下代码:它会给你传递给它的对象提供引用级别(只需做一点更改,你可以将其更改为返回指针引用的对象,只需使用注释而不是acual代码,并直接使用countPartial):

template <class T> int countPartial(T *x,int depth)
//use template <class T> T& countPartial(T *x)
{
    return countPartial(*x,depth+1);
    //return countPartial(*x);
}
template <class T> int countPartial(T &x,int depth)
//use template <class T> T& countPartial(T &x)
{
    return depth;
    //return x;
}
template <class T> int count(T x)
{
    return countPartial(x,0);
}

这可能会解决您的问题T是模板。funcptr函数的ptr。

int callfunc( T ptr)
{
depth = 0;
if ( typeof(ptr)!=  typeof(funcptr))
{

depth++;
depth = depth + callfunc(*ptr);
}
return depth;
}
相关文章: