使用可变参数模板函数包装基于省略号的函数
Wrapping ellipsis-based function with variadic template function
我正在尝试包装来自外部库 (libpqxx) 的函数“prepared(.)
”。所述函数接受可变数量的参数。这是通过连续使用多个 operator()
来实现的。一个 operator()
公关。参数,像这样:
pqxx::connection connection(connection_str);
connection.prepare("update_person", "UPDATE person SET name = WHERE id = AND version = ");
pqxx::work w(connection);
// The following executes prepared statement.
// The number of arguments is variable. Notice
// the syntax with multiple () in succession...
w.prepared("update_person")("Jack")(1)(0).exec();
我正在尝试使用可变参数模板函数来包装最后一个函数,如下所示:
template<typename... T>
pqxx::result exec_prepared(const std::string& name, const T&... args) const {
return w.prepared(name)(args...).exec();
}
...但它不起作用。代码可以编译,但我收到一个运行时错误,指出参数的数量与给定 prepared-sql-statement 的预期参数数量不匹配。
有人可以解释一下如何使用可变参数模板包装这种类型的函数吗?谢谢!
如果包args
表示三个参数,那么
return w.prepared(name)(args...).exec();
扩展到
return w.prepared(name)(args0, args1, args2).exec();
不同于
return w.prepared(name)(args0)(args1)(args2).exec();
你需要的。
看来您需要一个每次递归应用一个参数的辅助函数:
private:
template <typename E>
static E&& apply_prepared_args(E&& expr) {
return std::forward<E>(expr);
}
template <typename E, typename First, typename... Rest>
static decltype(auto) apply_prepared_args(
E&& expr, const First& first, const Rest& ...rest) {
return apply_prepared_args(std::forward<E>(expr)(first), rest...);
}
public:
template<typename... T>
pqxx::result exec_prepared(
const std::string& name, const T&... args) const {
return apply_prepared_args(w.prepared(name), args...).exec();
}
Aschepler 向您解释了您的实际代码有什么问题。
不确定 libpqxx 库是如何工作的,但我可以尝试进行有根据的猜测并提出一个非常简单的解决方案。
像下面的代码(抱歉:未经测试)怎么样?
(并由 aschepler 更正;谢谢!)
template <typename ... Ts>
pqxx::result exec_prepared (std::string const & name,
Ts const & ... args) const
{
using unused = int[];
auto p = w.prepared(name);
(void)unused { 0, (p = p(args), 0)... };
return p.exec();
}
如果你可以使用 C++17,我想你可以简化(避免未使用的技巧)如下(再次抱歉:未测试)
pqxx::result exec_prepared (std::string const & name,
Ts const & ... args) const
{
auto p = w.prepared(name);
(p = p(args), ...);
return p.exec();
}
我会弃牌。
template<class F>
struct invoke_by_times_t;
template<class F>
invoke_by_times_t<F> invoke_by_times(F&&)
template<class F>
struct invoke_by_times_t {
F f;
template<class Rhs>
auto operator*(Rhs&&rhs)&&{
return invoke_by_times( std::forward<F>(f)(std::forward<Rhs>(rhs)) );
}
};
这让我们可以这样做:
w.prepared("update_person")("Jack")(1)(0).exec();
和
(invoke_by_times([&](auto&&x){ return w.prepared(x); })*("update_person")*("Jack")*(1)*(0)).f.exec();
现在这不是很有用,但是对于 C++17 来说这是对 args 的简单折叠!
在c++14中,我们可以写乘积:
template<class A1, class A2>
delctype(auto) product(A1&& a1, A2&& a2){
return std::forward<A1>(a1)*std::forward<A2>(a2);
}
template<class A1, class A2, class...Args>
delctype(auto) product(A1&& a1, A2&& a2, Args&&...args){
return product(std::forward<A1>(a1)*std::forward<A2>(a2), std::forward<Args>(args)...);
}
给我们:
product(invoke_by_times([&](auto&&x){ return w.prepared(x); }), "update_person", "Jack", 1, 0).f.exec();
我正在尝试包装来自外部库 (libpqxx) 的函数“prepared(.)
”。所述函数接受可变数量的参数。这是通过连续使用多个 operator()
来实现的。一个 operator()
公关。参数,像这样:
pqxx::connection connection(connection_str);
connection.prepare("update_person", "UPDATE person SET name = WHERE id = AND version = ");
pqxx::work w(connection);
// The following executes prepared statement.
// The number of arguments is variable. Notice
// the syntax with multiple () in succession...
w.prepared("update_person")("Jack")(1)(0).exec();
我正在尝试使用可变参数模板函数来包装最后一个函数,如下所示:
template<typename... T>
pqxx::result exec_prepared(const std::string& name, const T&... args) const {
return w.prepared(name)(args...).exec();
}
...但它不起作用。代码可以编译,但我收到一个运行时错误,指出参数的数量与给定 prepared-sql-statement 的预期参数数量不匹配。
有人可以解释一下如何使用可变参数模板包装这种类型的函数吗?谢谢!
如果包args
表示三个参数,那么
return w.prepared(name)(args...).exec();
扩展到
return w.prepared(name)(args0, args1, args2).exec();
不同于
return w.prepared(name)(args0)(args1)(args2).exec();
你需要的。
看来您需要一个每次递归应用一个参数的辅助函数:
private:
template <typename E>
static E&& apply_prepared_args(E&& expr) {
return std::forward<E>(expr);
}
template <typename E, typename First, typename... Rest>
static decltype(auto) apply_prepared_args(
E&& expr, const First& first, const Rest& ...rest) {
return apply_prepared_args(std::forward<E>(expr)(first), rest...);
}
public:
template<typename... T>
pqxx::result exec_prepared(
const std::string& name, const T&... args) const {
return apply_prepared_args(w.prepared(name), args...).exec();
}
Aschepler 向您解释了您的实际代码有什么问题。
不确定 libpqxx 库是如何工作的,但我可以尝试进行有根据的猜测并提出一个非常简单的解决方案。
像下面的代码(抱歉:未经测试)怎么样? (并由 aschepler 更正;谢谢!)
template <typename ... Ts>
pqxx::result exec_prepared (std::string const & name,
Ts const & ... args) const
{
using unused = int[];
auto p = w.prepared(name);
(void)unused { 0, (p = p(args), 0)... };
return p.exec();
}
如果你可以使用 C++17,我想你可以简化(避免未使用的技巧)如下(再次抱歉:未测试)
pqxx::result exec_prepared (std::string const & name,
Ts const & ... args) const
{
auto p = w.prepared(name);
(p = p(args), ...);
return p.exec();
}
我会弃牌。
template<class F>
struct invoke_by_times_t;
template<class F>
invoke_by_times_t<F> invoke_by_times(F&&)
template<class F>
struct invoke_by_times_t {
F f;
template<class Rhs>
auto operator*(Rhs&&rhs)&&{
return invoke_by_times( std::forward<F>(f)(std::forward<Rhs>(rhs)) );
}
};
这让我们可以这样做:
w.prepared("update_person")("Jack")(1)(0).exec();
和
(invoke_by_times([&](auto&&x){ return w.prepared(x); })*("update_person")*("Jack")*(1)*(0)).f.exec();
现在这不是很有用,但是对于 C++17 来说这是对 args 的简单折叠!
在c++14中,我们可以写乘积:
template<class A1, class A2>
delctype(auto) product(A1&& a1, A2&& a2){
return std::forward<A1>(a1)*std::forward<A2>(a2);
}
template<class A1, class A2, class...Args>
delctype(auto) product(A1&& a1, A2&& a2, Args&&...args){
return product(std::forward<A1>(a1)*std::forward<A2>(a2), std::forward<Args>(args)...);
}
给我们:
product(invoke_by_times([&](auto&&x){ return w.prepared(x); }), "update_person", "Jack", 1, 0).f.exec();