C ++:给定指针类型,如何恢复指针类型
c++: Given a pointer type how can one recover the pointee type?
给定:
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_if
,std::is_pointer<T>
和std::remove_pointer<T>
只有在您有C++11
的情况下才可用。如果你不这样做,你可以将std::tr1::is_pointer
或boost::is_pointer
与boost::enable_if
(或boost::enable_if_c
(或自己编写的enable_if
一起使用(看看这里如何做到这一点,这是非常微不足道的(。 remove_pointer
也可以作为std::tr1::remove_pointer
和boost::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_const
或 boost::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"
}
- C++中的双指针类型转换
- C++默认情况下,指针类型数组的元素是否保证初始化为 nullptr?
- 将类指针类型转换为键时出错
- 错误:表达式必须具有算术、无作用域枚举或带有运算符重载的指针类型
- C++在一个映射中存储不同的指针类型(并处理销毁)
- 指针类型类成员的动态强制转换的恒定性是什么?
- 我正在尝试将表的地址传递给要在另一个函数中使用的指针,但得到不兼容的指针类型
- 在将派生类指针类型转换为派生类指针后,从基类指针调用派生类函数
- 如何使用静态多态性在 int 和指针类型之间进行转换?
- STL 函数和函数类型与函数指针类型
- 如何调用指针类型的方法(禁用多态性)?
- 为什么新表达式可以正确生成指针类型,即使它应该返回 void*?
- 对于非常量指针类型的参数,未调用具有常量指针模板类型参数的功能
- 是否允许调用方对我的 Builder 类使用任何指针类型(包括智能指针)?
- OPENCL 警告:不兼容的指针类型将'float __global[16]'传递给类型为 '__global float4 的参数 *
- 专门用于"direct"函数类型(与函数指针类型相对)
- 指向成员的指针类型和模板
- 返回对常量结构(指针类型)成员的引用:明显的左值到右值转换
- 在C++17中,为什么类模板和函数模板的指针类型推导明显不一致
- 为什么允许将整型、枚举和指向成员的指针类型reinterpret_cast到自身?