c++;具有可变参数的模板函数 是否可以编写一个C++模板函数,它可以采用不同类型的输入变量变量(输入数量可以限制为10)? 例如,以函数sql\u exec()为例,该函数执行sql查询字符串,并将结果行保存在所提供类型的std向量中,即 std::vector<double> x,y; std::vector<std::string> s; std::string query="select * from ..."; sql_exec(query, s,x,y); // error if less than 3 rows or conversion not possible
但实际上它是用gcc和c++;具有可变参数的模板函数 是否可以编写一个C++模板函数,它可以采用不同类型的输入变量变量(输入数量可以限制为10)? 例如,以函数sql\u exec()为例,该函数执行sql查询字符串,并将结果行保存在所提供类型的std向量中,即 std::vector<double> x,y; std::vector<std::string> s; std::string query="select * from ..."; sql_exec(query, s,x,y); // error if less than 3 rows or conversion not possible,c++,templates,template-meta-programming,variadic-functions,C++,Templates,Template Meta Programming,Variadic Functions,但实际上它是用gcc和-std=c++0x编译的。但是,显然sql\u query()仍然不接受可变长度的输入,需要使用两个向量调用。另外,我希望在大多数当前的编译器上使用一些可移植的东西。有什么明显我忽略的吗?我知道我可以改变设计,也许可以使用boost::tuple或其他东西,但我希望有这样一个简单的界面。在C++0x中,这是通过可变模板实现的(参数的数量可能会很大,限制是特定于实现的) 在C++03中,这是通过让预处理器宏生成大量不同算术性的模板函数来模拟的(参见Boost.preproc
-std=c++0x
编译的。但是,显然sql\u query()
仍然不接受可变长度的输入,需要使用两个向量调用。另外,我希望在大多数当前的编译器上使用一些可移植的东西。有什么明显我忽略的吗?我知道我可以改变设计,也许可以使用boost::tuple
或其他东西,但我希望有这样一个简单的界面。在C++0x中,这是通过可变模板实现的(参数的数量可能会很大,限制是特定于实现的)
在C++03中,这是通过让预处理器宏生成大量不同算术性的模板函数来模拟的(参见Boost.preprocessor)
我已经使用C++03技术生成了从1到10个参数的“bind”,它工作得很好。如上所述,Boost。如果C++0x不可用,预处理器是一种方法,尽管需要一段时间才能习惯语法。下面的示例演示如何使用Boost.Preprocessor定义具有可变(但数量有限)参数的函数
#include <boost/preprocessor/repetition.hpp>
#include <boost/preprocessor/iteration/local.hpp>
#include <boost/preprocessor/iteration/iterate.hpp>
#define MAX_PARAMS 2
class sql {
public:
// definition of the function in macro form
#define SQL_QUERY_DEF(z, n, unused) \
template <BOOST_PP_ENUM_PARAMS(n, class T)> \
void query(const std::string& query, \
BOOST_PP_ENUM_BINARY_PARAMS(n, const T, & x) );
// does the actual code replication of SQL_QUERY_DEF
#define BOOST_PP_LOCAL_MACRO(n) SQL_QUERY_DEF(~, n, ~)
#define BOOST_PP_LOCAL_LIMITS (1, MAX_PARAMS)
#include BOOST_PP_LOCAL_ITERATE()
...
};
// two helper functions:
// expands to var0.clear(); var1.clear(); ...
#define SQL_VECTOR_CLEAR(z,i,var) var##i.clear();
// expands to var0.push_back(this->get_col<T0>(0); ...
#define SQL_VECTOR_PUSH_BACK(z,i,var) var##i.push_back(this->get_col<T##i>(i));
// definition of the function in macro form
#define SQL_QUERY(z, n, unused) \
template <BOOST_PP_ENUM_PARAMS(n, class T)> \
void sql::query(const std::string& query, \
BOOST_PP_ENUM_BINARY_PARAMS(n, std::vector< T,>& x) ){ \
this->do_query(query); \
if(this->num_cols()<n){ \
throw std::runtime_error(); \
} \
BOOST_PP_REPEAT(n, SQL_VECTOR_CLEAR, x) \
while(this->is_open()) { \
BOOST_PP_REPEAT(n, SQL_VECTOR_PUSH_BACK, x) \
this->step(); \
} \
}
// does the actual code replication of SQL_QUERY
#define BOOST_PP_LOCAL_MACRO(n) SQL_QUERY(~, n, ~)
#define BOOST_PP_LOCAL_LIMITS (1, MAX_PARAMS)
#include BOOST_PP_LOCAL_ITERATE()
#包括
#包括
#包括
#定义最大参数2
类sql{
公众:
//宏形式的函数定义
#定义SQL_查询_定义(z,n,未使用)\
模板\
void查询(const std::string和query\
BOOST_PP_ENUM_BINARY_参数(n,const T,&x));
//SQL_QUERY_DEF的实际代码复制
#定义BOOST\u PP\u LOCAL\u宏(n)SQL\u QUERY\u DEF(~,n,~)
#定义增压PP本地限制(1,最大参数)
#包括BOOST_PP_LOCAL_ITERATE()
...
};
//两个辅助功能:
//展开为var0.clear();var1.clear()。。。
#定义SQL_VECTOR_CLEAR(z,i,var)var#i.CLEAR();
//扩展到var0。向后推(此->获取列(0)。。。
#定义SQL_VECTOR_PUSH_BACK(z,i,var)var#i.PUSH_BACK(this->get_col(i));
//宏形式的函数定义
#定义SQL_查询(z,n,未使用)\
模板\
void sql::query(const std::string和query)\
BOOST_PP_ENUM_BINARY_参数(n,std::vector&x)){\
此->执行查询(查询)\
如果(this->num\u cols()是\u open()){\
BOOST\u PP\u REPEAT(n,SQL\u VECTOR\u PUSH\u BACK,x)\
此->步骤()\
} \
}
//SQL\u查询的实际代码复制
#定义BOOST\u PP\u LOCAL\u宏(n)SQL\u查询(~,n,~)
#定义增压PP本地限制(1,最大参数)
#包括BOOST_PP_LOCAL_ITERATE()
预处理器将其扩展为:
$ g++ -P -E sql.cpp | astyle
class sql {
public:
template < class T0> void query(const std::string& query, const T0 & x0 );
template < class T0 , class T1> void query(const std::string& query, const T0 & x0 , const T1 & x1 );
...
};
template < class T0> void sql::query(const std::string& query, std::vector< T0 >& x0 ) {
this->do_query(query);
if(this->num_cols()<1) {
throw std::runtime_error();
}
x0.clear();
while(this->is_open()) {
x0.push_back(this->get_col<T0>(0));
this->step();
}
}
template < class T0 , class T1> void sql::query(const std::string& query, std::vector< T0 >& x0 , std::vector< T1 >& x1 ) {
this->do_query(query);
if(this->num_cols()<2) {
throw std::runtime_error();
}
x0.clear();
x1.clear();
while(this->is_open()) {
x0.push_back(this->get_col<T0>(0));
x1.push_back(this->get_col<T1>(1));
this->step();
}
}
$g++-P-esql.cpp | astyle
类sql{
公众:
模板无效查询(const std::string&query,const T0&x0);
模板无效查询(常量std::string&query,常量T0&x0,常量T1&x1);
...
};
模板无效sql::查询(const std::string&query,std::vector&x0){
此->执行查询(查询);
如果(此->num\u cols()是\u open()){
x0.向后推(此->获取列(0));
此->步骤();
}
}
模板<类T0,类T1>无效sql::查询(常量std::字符串和查询,std::vector&x0,std::vector&x1){
此->执行查询(查询);
如果(此->num\u cols()是\u open()){
x0.向后推(此->获取列(0));
x1.向后推(此->获取列(1));
此->步骤();
}
}
注意,这里我们不能使用
BOOST\u PP\u REPEAT(MAX\u PARAMS,SQL\u QUERY,~)
,因为它用0个参数开始复制,但我们需要从1开始,这就是为什么BOOST\u PP\u LOCAL\u ITERATE()
是必需的,它更灵活。像这样吗?是的,谢谢。但是,我试图避免使用C++0x以及递归的函数定义方式,在这种情况下,这会使事情变得困难。因为我对有限的最大输入数感到满意,也许还有另一种方法?几乎肯定有一种方法可以优雅地使用可变模板。这基于模板的思维需要一点习惯,但它可能比没有可变模板的任何东西都要简单得多。
#include <boost/preprocessor/repetition.hpp>
#include <boost/preprocessor/iteration/local.hpp>
#include <boost/preprocessor/iteration/iterate.hpp>
#define MAX_PARAMS 2
class sql {
public:
// definition of the function in macro form
#define SQL_QUERY_DEF(z, n, unused) \
template <BOOST_PP_ENUM_PARAMS(n, class T)> \
void query(const std::string& query, \
BOOST_PP_ENUM_BINARY_PARAMS(n, const T, & x) );
// does the actual code replication of SQL_QUERY_DEF
#define BOOST_PP_LOCAL_MACRO(n) SQL_QUERY_DEF(~, n, ~)
#define BOOST_PP_LOCAL_LIMITS (1, MAX_PARAMS)
#include BOOST_PP_LOCAL_ITERATE()
...
};
// two helper functions:
// expands to var0.clear(); var1.clear(); ...
#define SQL_VECTOR_CLEAR(z,i,var) var##i.clear();
// expands to var0.push_back(this->get_col<T0>(0); ...
#define SQL_VECTOR_PUSH_BACK(z,i,var) var##i.push_back(this->get_col<T##i>(i));
// definition of the function in macro form
#define SQL_QUERY(z, n, unused) \
template <BOOST_PP_ENUM_PARAMS(n, class T)> \
void sql::query(const std::string& query, \
BOOST_PP_ENUM_BINARY_PARAMS(n, std::vector< T,>& x) ){ \
this->do_query(query); \
if(this->num_cols()<n){ \
throw std::runtime_error(); \
} \
BOOST_PP_REPEAT(n, SQL_VECTOR_CLEAR, x) \
while(this->is_open()) { \
BOOST_PP_REPEAT(n, SQL_VECTOR_PUSH_BACK, x) \
this->step(); \
} \
}
// does the actual code replication of SQL_QUERY
#define BOOST_PP_LOCAL_MACRO(n) SQL_QUERY(~, n, ~)
#define BOOST_PP_LOCAL_LIMITS (1, MAX_PARAMS)
#include BOOST_PP_LOCAL_ITERATE()
$ g++ -P -E sql.cpp | astyle
class sql {
public:
template < class T0> void query(const std::string& query, const T0 & x0 );
template < class T0 , class T1> void query(const std::string& query, const T0 & x0 , const T1 & x1 );
...
};
template < class T0> void sql::query(const std::string& query, std::vector< T0 >& x0 ) {
this->do_query(query);
if(this->num_cols()<1) {
throw std::runtime_error();
}
x0.clear();
while(this->is_open()) {
x0.push_back(this->get_col<T0>(0));
this->step();
}
}
template < class T0 , class T1> void sql::query(const std::string& query, std::vector< T0 >& x0 , std::vector< T1 >& x1 ) {
this->do_query(query);
if(this->num_cols()<2) {
throw std::runtime_error();
}
x0.clear();
x1.clear();
while(this->is_open()) {
x0.push_back(this->get_col<T0>(0));
x1.push_back(this->get_col<T1>(1));
this->step();
}
}