C ++:给定指针类型,如何恢复指针类型

c++: Given a pointer type how can one recover the pointee type?

本文关键字:指针 类型 何恢复 恢复 定指      更新时间:2023-10-16

给定:

struct Field
{
  template<class T> T Value() const
  {
    // ???
  }
  template<class S> S SimpleValue() const
  {
    return *reinterpret_cast<const S *>(GetVoidPointerToTheActualValue());
  }
  template<class P> const P *PointerValue() const
  {
    return reinterpret_cast<const P *>(GetVoidPointerToTheActualValue());
  }
};

如何实现 Field::Value<T>() 方法,以便编译器自动调度到:

  • Field::PointerValue<P> T是否真的P*
  • Field::SimpleValue<S>否则

此外,可以保证T既不是引用也不是指针到指针类型。

谢谢。

编辑

@Grizzly - 我已经尝试过您的建议,不幸的是它在编译Value<LPCWSTR>()期间失败了:

1>  playmssqlce.cpp
1>c:devinternalplaymssqlceplaymssqlce.cpp(75): error C2668: 'sqlserver::Field::Value' : ambiguous call to overloaded function
1>          c:devinternalplaymssqlcesqlserverfield.h(19): could be 'std::tr1::enable_if<_Test,_Type> sqlserver::Field::Value<LPCWSTR>(void) const'
1>          with
1>          [
1>              _Test=false,
1>              _Type=LPCWSTR
1>          ]
1>          c:devinternalplaymssqlcesqlserverfield.h(18): or       'std::tr1::enable_if<_Test,_Type> sqlserver::Field::Value<LPCWSTR>(void) const'
1>          with
1>          [
1>              _Test=true,
1>              _Type=LPCWSTR
1>          ]
1>          while trying to match the argument list '(void)'

我不清楚为什么,因为你的建议感觉是正确的。顺便说一句,我正在使用Visual Studio 2010。

编辑2

修复愚蠢的错误后,我仍然有问题。所以,这是我所拥有的:

struct Field
{
  template<class T> typename enable_if<is_pointer<T>::value, T>::type Value() const { return PointerValue(); }
  template<class T> typename enable_if<!is_pointer<T>::value, T>::type Value() const { return SimpleValue(); }
  template<class T> T SimpleValue() const         { return *reinterpret_cast<const T *>(GetVoidPointerToTheActualValue()); }
  template<class T> const T *PointerValue() const { return reinterpret_cast<const T *>(GetVoidPointerToTheActualValue()); }
};

我正在尝试编译f.Value<const wchar_t *>(),但得到这个:

1>  playmssqlce.cpp
1>c:devinternalplaymssqlcesqlserverfield.h(18): error C2783: 'const T *sqlserver::Field::PointerValue(void) const' : could not deduce template argument for 'T'
1>          c:devinternalplaymssqlcesqlserverfield.h(42) : see declaration of 'sqlserver::Field::PointerValue'
1>          c:devinternalplaymssqlceplaymssqlce.cpp(75) : see reference to function template instantiation 'const wchar_t *sqlserver::Field::Value<const wchar_t*>(void) const' being compiled

我现在做错了什么?

谢谢。

编辑3

愚蠢的我。注意到灰熊的变化:

template<class T> typename enable_if<is_pointer<T>::value, T>::type Value() const { return PointerValue<typename std::remove_pointer<T>::type>(); }
template<class T> typename enable_if<!is_pointer<T>::value, T>::type Value() const { return SimpleValue<T>(); }

现在工作。

您可以使用

enable_if

struct Field {
  /*Other methods of Field*/
  template<class T> 
  typename std::enable_if<std::is_pointer<T>::value, T>::type Value() const {
    return this->PointerValue<typename std::remove_pointer<T>::type>();
  }
  template<class T> 
  typename  std::enable_if<!std::is_pointer<T>::value, T>::type Value() const {
    return this->SimpleValue<T>();
  }
};

当然std::enable_ifstd::is_pointer<T>std::remove_pointer<T>只有在您有C++11的情况下才可用。如果你不这样做,你可以将std::tr1::is_pointerboost::is_pointerboost::enable_if(或boost::enable_if_c(或自己编写的enable_if一起使用(看看这里如何做到这一点,这是非常微不足道的(。 remove_pointer也可以作为std::tr1::remove_pointerboost::remove_pointer

但是,根据您想要的内容,它可能仍然不能做您想要的,因为我编写它的方式您需要const P*传递给Value(),因为这就是PointerValue()返回的内容。如果要传递P*并取回const P*,可以将其更改为以下内容:

typename std::enable_if<
    std::is_pointer<T>::value, typename 
    std::add_const<typename 
        std::remove_pointer<T>::type
    >::type*
>::type Value() const;  
如果您

没有 c++11,请再次使用 std::tr1::add_constboost::add_const

您希望函数模板具有两种不同的行为,具体取决于实例化它的参数类型。这需要模板专用化。在这种情况下,由于您希望专门针对所有指针类型,因此您需要的是部分模板专用化。

函数模板不支持部分专用化:解决方案是使用帮助程序类模板来执行操作:

template < typename T >
struct getValue
{
    static T apply() { default behavior }
};
template < typename T>
struct getValue< T * >
{
    static T * apply() { behavior for pointer types }
};

然后,可以在成员函数模板中使用此帮助程序类。但是,由于您需要访问 Field 实例中的某些数据,因此您需要将其传递给帮助程序类。

另一件事是Field::value的返回类型取决于模板参数。要确定正确的返回类型,一个好的解决方案是在帮助程序类中有一个 typedef,可以在声明 Field::value 时检索该 typedef。

以下是此解决方案的完整代码:

#include <iostream>
namespace detail { template < typename T > struct getValue; }
class Field
{
  public:
    void * getVoidPointerToTheActualValue() const;
    template< class T >
    typename detail::getValue< T >::result_type value() const;
  private:
    void * actualValue_;
};
namespace detail {
template < typename T >
struct getValue
{
    typedef T result_type;
    static result_type apply( Field const & f )
    {
        std::cout << "simpleValue" << 'n';
        return *reinterpret_cast< const T * >( 
                f.getVoidPointerToTheActualValue() );
    }
};
template < typename T >
struct getValue< T * >
{
    typedef T const * result_type;
    static result_type apply( Field const & f )
    {
        std::cout << "pointerValue" << 'n';
        return reinterpret_cast< const T * >(
                f.getVoidPointerToTheActualValue() );
    }
};
} //namespace detail

void * Field::getVoidPointerToTheActualValue() const
{
    return actualValue_;
}
template< class T >
typename detail::getValue< T >::result_type Field::value() const
{
    return detail::getValue< T >::apply( *this );
}

int main()
{
    Field f;
    f.value< int >();   //prints "simpleValue"
    f.value< int * >(); //prints "pointerValue"
}
相关文章: