《C++程序设计语言》(第四版)一书。第28.4章(第796页)解释了enable_if并给出了使operator->()成为条件定义的示例。书中的例子只是一个代码片段,我将其完成为程序如下:
#include <iostream>
#include <type_traits>
#include <complex>
using namespace std;
template<bool B, typename T>
using Enable_if=typename std::enable_if<B,T>::type;
template<typename T>
constexpr bool Is_class(){ //the book example misses constexpr
return std::is_class<T>::value;
}
template<typename T>
class Smart_pointer{
public:
Smart_pointer(T* p):data(p){
}
T& operator*();
Enable_if<Is_class<T>(),T>* operator->(){
return data;
}
~Smart_pointer(){
delete data;
}
private:
T* data;
};
int main()
{
Smart_pointer<double> p(new double); //compiling error in g++ 4.7.2: no type named 'type' in 'struct std::enable_if<false, double>'
//Smart_pointer<std::complex<double>> q(new std::complex<double>);//compile successfully.
}
上面的代码无法在 gcc 4.7.2 中编译。编译器抱怨:错误:“struct std::enable_if”中没有名为“type”的类型
根据书中的解释,如果T不是类,operator->()将被忽略。但是,这并不能解释编译错误。编译错误表明相反,即使 T 不是类,operator->() 的定义也不会被忽略。这篇文章似乎解释了编译错误std::enable_if 有条件地编译成员函数 https://stackoverflow.com/questions/6972368/stdenable-if-to-conditionally-compile-a-member-function。但这篇文章似乎与书中的解释不一致。任何人都可以帮忙解释一下成员函数的enable_if的用法吗?在上面的例子中,如果我确实想仅在 T 是类时定义operator->(),是否有一个干净而优雅的解决方案?谢谢。
非常感谢您的回复。还有另一种基于重载的解决方法(我不会说它比其他发布的解决方案更好)
template<typename T>
T* Smart_pointer<T>::operator->(){
op_arrow(std::integral_constant<bool,Is_class<T>()>());
}
private:
T* op_arrow(std::true_type){
return data;
}
T* op_arrow(std::false_type);
首先,正如 @jrok 和您链接到的帖子所提到的:
你必须有一个模板函数才能使用enable_if
。但在您的特定情况下这不是一个好主意,因为没有理由这样做operator->
模板化。而且,这也是行不通的!因为没有办法实例化一个特定的操作符->()!它没有(也不能)任何参数,并且当您指定它时没有语法可以指定它call它在某个物体上!所以,T
(或任何虚拟类型)将/无法从此调用中推断出来。
因此,作为解决方法,您可以使用编译时条件继承。即像这样:
template <typename T, bool IsClass>
struct smart_base
{
struct base {};
};
template <typename T>
struct smart_base<T, true>
{
struct base
{
T* operator->()
{
// do that ever you wanted to do
}
};
};
template <typename T>
struct smart : public smart_base<T, std::is_class<T>::value>::base
{
// depending on T here you have, or have no operator-> inherited
};
你必须明白,有operator->
实际上在你的基类中需要将一些函数和/或数据成员移动到基类的基类:)或者你可以使用 CRTP 技术从基类访问派生类的成员:)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)