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> }

|