解决C++函数模板重载时出现的歧义,函数模板隐藏技术
2013-03-24 00:23
513 查看
函数重载是C++中实现静态多态的重要机制,在定义函数重载时,特别是在有函数模板加入时,更需要小心定义参数,防止歧义的出现
举例来说,有下面两个重载函数,用于执行数据库查询并返回查询结果,分别对应到查单个值和查列表两个版本,模板类型参数V是查询结果的类型:
template<class V>
long query(const std::string &strSql, V *pv, CDBConn *poConn=NULL);
template<class V>
long query(const std::string &strSql, long *plLen, V *pv, CDBConn *poConn=NULL);
实际以long类型调用第一个重载版本函数时:
CDBConn *pcon = NULL;
long lValue = 0;
query("select count(*) from tbl_data", &lValue, pcon);
编译器会提示歧义:
1>------ Build started: Project: test, Configuration: Debug Win32 ------
1>Compiling...
1>test.cpp
1>e:\cj\boost_test\test\test.cpp(321) : error C2668: 'query' : ambiguous call to overloaded function
1> e:\cj\boost_test\test\test.cpp(314): could be 'long query<CDBConn>(const std::string &,long *,V *,CDBConn *)'
1> with
1> [
1> V=CDBConn
1> ]
1> e:\cj\boost_test\test\test.cpp(310): or 'long query<long>(const std::string &,V *,CDBConn *)'
1> with
1> [
1> V=long
1> ]
1> while trying to match the argument list '(const char [1], long *, CDBConn *)'
1>Build log was saved at "file://e:\cj\boost_test\test\Debug\BuildLog.htm"
1>test - 1 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
编译错误提示表示两个版本都能满足参数类型的匹配,即:
如果选择第一个版本,V的类型就被推导为long类型;而如果选择第二个版本,V的类型被推导为CDBConn类型,由于最后一个连接参数有缺省值可以不填
看来只需要将第二个重载版本的最后一个参数的缺省值去掉,不提供缺省值就可以解决这个问题了。
那有没有鱼和熊掌兼得的方法呢?
让第二个函数模板在V被推导成CDBConn时,不让自己生效不就行了!
这就是本文重点要介绍的函数模板隐藏技术了^^
原理:如果一个函数模板不能成功推导自己的所有模板参数,编译器就不会让它参与重载
提示:通过在函数的返回值类型上下工夫,就可以不修改函数参数的原型来达到我们的目的了。
到这里大家可以自己先想想实现方案,实现代码稍后附上^^
-------------------------------------------------------------------------------
实现代码:
按如下代码修改第二个重载版本的返回值类型:
template<class V> typename enable_if_not_conn_type<V>::type
query(const std::string &strSql, long *plLen, V *pv, CDBConn *poConn=NULL);
上面模板enable_if_not_conn_type对类型CDBConn的特化版本无法推导出type类型:
template <class T>
struct enable_if_not_conn_type
{
typedef long type;
};
template <>
struct enable_if_not_conn_type<CDBConn> //特化版本没有定义type类型
{
};
更通用的模板定义如下:
template <class T1, class T2>
struct enable_if_not_type
{
typedef long type;
};
template <class T>
struct enable_if_not_type<T,T>
{
};
使用上面模板,重新定义函数:
template<class V> typename enable_if_not_type<V,CDBConn>::type
query(const std::string &strSql, long *plLen, V *pv, CDBConn *poConn=NULL);
举例来说,有下面两个重载函数,用于执行数据库查询并返回查询结果,分别对应到查单个值和查列表两个版本,模板类型参数V是查询结果的类型:
template<class V>
long query(const std::string &strSql, V *pv, CDBConn *poConn=NULL);
template<class V>
long query(const std::string &strSql, long *plLen, V *pv, CDBConn *poConn=NULL);
实际以long类型调用第一个重载版本函数时:
CDBConn *pcon = NULL;
long lValue = 0;
query("select count(*) from tbl_data", &lValue, pcon);
编译器会提示歧义:
1>------ Build started: Project: test, Configuration: Debug Win32 ------
1>Compiling...
1>test.cpp
1>e:\cj\boost_test\test\test.cpp(321) : error C2668: 'query' : ambiguous call to overloaded function
1> e:\cj\boost_test\test\test.cpp(314): could be 'long query<CDBConn>(const std::string &,long *,V *,CDBConn *)'
1> with
1> [
1> V=CDBConn
1> ]
1> e:\cj\boost_test\test\test.cpp(310): or 'long query<long>(const std::string &,V *,CDBConn *)'
1> with
1> [
1> V=long
1> ]
1> while trying to match the argument list '(const char [1], long *, CDBConn *)'
1>Build log was saved at "file://e:\cj\boost_test\test\Debug\BuildLog.htm"
1>test - 1 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
编译错误提示表示两个版本都能满足参数类型的匹配,即:
如果选择第一个版本,V的类型就被推导为long类型;而如果选择第二个版本,V的类型被推导为CDBConn类型,由于最后一个连接参数有缺省值可以不填
看来只需要将第二个重载版本的最后一个参数的缺省值去掉,不提供缺省值就可以解决这个问题了。
那有没有鱼和熊掌兼得的方法呢?
让第二个函数模板在V被推导成CDBConn时,不让自己生效不就行了!
这就是本文重点要介绍的函数模板隐藏技术了^^
原理:如果一个函数模板不能成功推导自己的所有模板参数,编译器就不会让它参与重载
提示:通过在函数的返回值类型上下工夫,就可以不修改函数参数的原型来达到我们的目的了。
到这里大家可以自己先想想实现方案,实现代码稍后附上^^
-------------------------------------------------------------------------------
实现代码:
按如下代码修改第二个重载版本的返回值类型:
template<class V> typename enable_if_not_conn_type<V>::type
query(const std::string &strSql, long *plLen, V *pv, CDBConn *poConn=NULL);
上面模板enable_if_not_conn_type对类型CDBConn的特化版本无法推导出type类型:
template <class T>
struct enable_if_not_conn_type
{
typedef long type;
};
template <>
struct enable_if_not_conn_type<CDBConn> //特化版本没有定义type类型
{
};
更通用的模板定义如下:
template <class T1, class T2>
struct enable_if_not_type
{
typedef long type;
};
template <class T>
struct enable_if_not_type<T,T>
{
};
使用上面模板,重新定义函数:
template<class V> typename enable_if_not_type<V,CDBConn>::type
query(const std::string &strSql, long *plLen, V *pv, CDBConn *poConn=NULL);
相关文章推荐
- [技术分享 - TMG 篇] TMG 选择网络模板时出现“未识别出网络适配器”错误的解决方法
- C++中成员函数的重载、覆盖与隐藏
- escape函数解决js中ajax传递中文出现乱码问题
- 技术QA:如何解决 Windows Server 2003 DC 启动后总是出现 LSASRV 40960 警告事件? 推荐
- “模板”学习笔记(4)-----如何解决函数模板的重载问题
- C++成员函数的 重载、隐藏、覆盖分析(转)
- c++成员函数的重载、覆盖(override)与隐藏
- 类成员函数的重载,覆盖和隐藏的区别
- 最近遇到了 timer1sec 定时调用的函数,出现了 时间久了,就不是每秒一次了,可能会慢的情况。如何解决呢?
- c++泛型编程中函数模板重载和模板特化同时存在时的查找规则
- 不可或缺 Windows Native (16) - C++: 函数重载, 缺省参数, 内联函数, 函数模板
- 成员函数的重载、覆盖与隐藏
- [C++基础]重载、覆盖、多态与函数隐藏(4)
- C++模板技术之method_thunk, 使用场景: C++中类成员函数作为回调函数
- 类成员函数的重载、覆盖和隐藏区别
- 刻录光驱不能访问出现函数不正确问题解决
- C++中成员函数的重载、覆盖和隐藏的区别
- C++学习 【4.4】 利用函数实现指定的功能---函数的重载、函数模板、有默认参数的函数
- 【转】王老师 C++ 函数重载和模板
- C++类成员函数的重载、覆盖和隐藏区别