Như đã nói ở trên, Boost.Preprocessor là cách để đi nếu C++ 0x không khả dụng, mặc dù phải mất một lúc để làm quen với cú pháp. Ví dụ dưới đây minh họa cách Boost.Preprocessor có thể được sử dụng để định nghĩa các hàm có số đối số biến (nhưng giới hạn).
#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()
Các preprocessor mở rộng này để:
$ 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();
}
}
Lưu ý, ở đây chúng tôi không thể sử dụng BOOST_PP_REPEAT(MAX_PARAMS, SQL_QUERY, ~)
khi nó bắt đầu nhân lên với 0 thông số nhưng chúng ta cần phải bắt đầu với 1, đó là lý do tại sao BOOST_PP_LOCAL_ITERATE()
là cần thiết mà linh hoạt hơn.
Như thế này? http://en.wikipedia.org/wiki/C%2B%2B0x#Variadic_templates – andrewdski
Vâng, cảm ơn. Tuy nhiên, tôi đang cố gắng tránh C++ 0x và cũng là cách đệ quy để xác định hàm sẽ làm cho mọi thứ trở nên khó khăn trong trường hợp này. Vì tôi hài lòng với số lượng đầu vào tối đa hạn chế có thể có một cách khác? – tom
có gần như chắc chắn một cách để sử dụng các mẫu variadic thanh lịch. Loại tư duy dựa trên mẫu này có một chút quen thuộc với, nhưng nó có thể sẽ đơn giản hơn nhiều so với bất cứ thứ gì bạn muốn tạo mà không có các mẫu variadic. –