假设:
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:\dev\internal\playmssqlce\playmssqlce.cpp(75): error C2668: 'sqlserver::Field::Value' : ambiguous call to overloaded function
1> c:\dev\internal\playmssqlce\sqlserverfield.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:\dev\internal\playmssqlce\sqlserverfield.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。
EDIT2
在解决了这个愚蠢的错误后,我仍然有问题。所以,这就是我所拥有的:
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:\dev\internal\playmssqlce\sqlserverfield.h(18): error C2783: 'const T *sqlserver::Field::PointerValue(void) const' : could not deduce template argument for 'T'
1> c:\dev\internal\playmssqlce\sqlserverfield.h(42) : see declaration of 'sqlserver::Field::PointerValue'
1> c:\dev\internal\playmssqlce\playmssqlce.cpp(75) : see reference to function template instantiation 'const wchar_t *sqlserver::Field::Value<const wchar_t*>(void) const' being compiled
我现在做错了什么?
感谢。
EDIT3
愚蠢的我。注意到Grizzly的变化:
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>(); }
立即行动。
答案 0 :(得分:3)
您可以使用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
一起使用(查看{{3对于如何做到这一点,它是非常微不足道的)。 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
答案 1 :(得分:1)
您希望您的函数模板具有两种不同的行为,具体取决于它实例化的参数类型。这需要模板专业化。在这种情况下,由于您希望专门针对所有指针类型,因此您需要的是部分模板特化。
函数模板不支持部分特化:解决方案是使用辅助类模板来执行操作:
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
的返回类型取决于模板参数。要确定什么是正确的返回类型,一个好的解决方案是在helper类中有一个typedef,可以在声明Field::value
时检索。
以下是此解决方案的完整代码:
#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"
}