<2007年10月>
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

常用链接

留言簿(2)

随笔分类(2)

随笔档案(2)

相册

C++编程技术

最新随笔

搜索

  •  

Boost如何让VC6以实现mem_fun可以接收返回值为void的成员函数

VC6自带的STL,mem_fun可以接收的成员函数返回值不能为void。
在<functional>文件中可以看到具体的实现代码为:

template<class _Return, class _Type>
class mem_fun_t
{
public:
//construction...

_Return operator()(_Type *_P) const
{return ((_P->*_FuncPtr)()); }
private:
//member function pointer ...
};

当_Return为void时,VC6会报一个编译错误:void' function returning a value。

有心想解决一下。首先,尝试使用static_cast。

_Return operator()(_Type *_P) const
{return static_cast<void)((_P->*_FuncPtr)()); }

发现报同样错误,看来VC6确实对标准支持一般。


然后当然想采用特化,对返回值类型进行void特化,但是VC6根本不支持部分特化,例如:

template<class _Type>
class mem_fun_t<void, _Type>
{..
};
报编译错误,重复的模板定义。 template class has already been defined as a non-template class

幸亏VC仍然支持完全特化,于是采用“增加一层“定律,由于只有返回值为void的时侯需要特别处理,
因此定义一个通用模板,然后对void进行完全特化:

template <class Return> struct return_trait
{
...
};


template<> struct return_trait<void>
{
...
};

下面的代码就是根据boost实现来的,简化了很多。毕竟阅读困难。

在这两者之间就可以对返回类型为void的情况进行特别处理了:
通用模板定义如下:
template <class Return> struct return_trait
{
template<class Return, class Type, class F>
struct inner_mem_fun_type
{
F func_;
inner_mem_fun_type(F f) : func_(f) {}

Return operator()(Type * type)
{
return (type->*func_)();
}

};

void的完全特化模板和上面一模一样,只是将
return (type->*func_)();
中的return去掉即可,就不多写了。其中boost使用了宏和#include来实现这个功能。

然后定义一个模板函数,用来自动实例化合适的模板类型;
template<class Return, class Type>
return_trait<Return>::inner_mem_fun_type<Return, Type, Return (Type::*)()>
mem_func(Return (Type::*f)())
{
return return_trait<Return>::inner_mem_fun_type<Return, Type, Return (Type::*)()>(f);
}

boost其实在mem_fn中又创建了一个间接层次,我发现上面直接返回内嵌类VC6也可以编译。可能是因为其他的编译器需要这样处理。其中inner_mem_fun_type接收3个参数,第3个参数为成员函数指针类型,完全可以由Return,Type确定,但是发现如果不加上这个,VC6出现internal compiler error。我在这上面就折腾了很久。也不知道boost是如何发现这个解决方法的。


举一反三,对于类似的部分特化的需求,在VC6下都应该可以使用该方法解决。
例如,一个模板类有2个类型参数T1, T2,其中需要对int, T2进行部分特化处理。

最标准的当然是
template<class Type1, class Type2> struct Foo
{
...
};

对int, Type2部分特化
template<class Type2> struct<int, Type2>Foo
{
...
};

前面说了VC6不支持这种部分特化,因此可以如下;
提出Type1,定义一个嵌套结构:
template<class Type1> struct type_traits
{
template<class Type1, class Type2> struct Foo
{
};
};

对Type1为int进行完全特化:
template<> struct type_traits<int>
{
template<class Type1, class Type2> struct Foo
{
};
};

使用之:

type_traits<double>::Foo<double, double> f1;
type_traits<int>::Foo<int, double> f2;

很好。但是毕竟毕竟繁琐,当然想搞个模板成员函数推演出来:

template<class Type1, class Type2>
type_traits<Type1>::Foo<Type1, Type2> make_foo(Type1 t1, Type2 t2)
{
return type_traits<Type1>::Foo<Type1, Type2>(t1, t2);
}

结果到这一步又是internal compiler error。

看来还又得学习boost中的,使用继承关系。再来:

定义一个Wapper class,从嵌套类type_traits::Foo派生

template<class Type1, class Type2>
struct FooWapper : public type_traits<Type1>::Foo<Type1, Type2>
{
FooWapper(Type1 t1, Type2 t2) : type_traits<Type1>::Foo<Type1, Type2>(t1, t2) {}
};

maker函数返回FooWapper模板类,而不是嵌套的模板类
template<class Type1, class Type2>
FooWapper<Type1, Type2> make_foo(Type1 t1, Type2 t2)
{
return FooWapper<Type1, Type2>(t1, t2);
}

再试:
make_foo(1, 2.0);
make_foo('a', 2.0);

编译成功。测试也对。通过这种手法,应该可以在VC6下解决一部分部分特化的问题,如果需要特化的类型以定的话。但是想对例如T*这种进行指针特化估计是没有希望了。不错。boost!

完整的源程序:

//通用Type1, Type2
template<class Type1> struct type_traits
{
template<class Type1, class Type2> struct Foo
{
Foo(Type1 t1, Type2 t2)
{
std::cout << "noint+type1" << std::endl;
}
};
};

//特化的int,Type2
template<> struct type_traits<int>
{
template<class Type1, class Type2> struct Foo
{
Foo(Type1 t1, Type2 t2)
{
std::cout << "int+type2" << std::endl;
}
};
};

//Wrapper 类
template<class Type1, class Type2>
struct FooWapper : public type_traits<Type1>::Foo<Type1, Type2>
{
FooWapper(Type1 t1, Type2 t2) : type_traits<Type1>::Foo<Type1, Type2>(t1, t2) {}
};


//maker函数用于推演
template<class Type1, class Type2>
FooWapper<Type1, Type2> inline make_foo(Type1 t1, Type2 t2)
{
return FooWapper<Type1, Type2>(t1, t2);
}

//测试程序
int main()
{
make_foo(1, 2.0); //调用特化的<int, type2>
make_foo('a', 2.0); //调用通用的<type1, type2>
}

posted on 2007-10-29 23:19 董礼 阅读(516) 评论(0)  编辑 收藏 引用 所属分类: 纯粹C++