使用 apply 函数时,我在以下代码中遇到歧义问题。它基于stackoverflow问题here。
1)我有一个帮助器类,因为不允许模板化函数作为指针:
template<typename TT, class...Ts>
struct selector_helper
{
static TT doSelect(Ts&&... params)
{
return iSelectable<Ts...>::select<TT>(std::forward<Ts>(params)...);
}
};
我尝试运行apply函数,但遇到了问题。我尝试了两个代码,但没有一个成功:
2.1)错误:apply:2个重载中没有一个可以转换所有参数类型
boost::tuple<Ts...> tpl;
return apply<T, Ts...>(selector_helper<T, Ts...>::doSelect, tpl);
2.2)这里我有两个错误:
错误3错误C2782:&#39; Ret apply(Ret(__ cdecl *)(Args ...),const boost :: tuples :: tuple&amp;)&#39; :模板参数&#39; Args&#39;含糊不清
boost::tuple<Ts...> tpl;
return apply(selector_helper<T, Ts...>::doSelect, tpl);
修改:更多解释:
两个示例都在select方法中运行,该方法在类中:
class database
{
template<typename T, typename...Ts>
T select_(const std::string& sql)
{
// apply examples
}
};
在这里打电话:
database db;
User result = db.select_<User, int, std::string, std::string>
("select id, email, name from credentials_tbl limit 1");
我错过了什么?
这是一个完整的例子,我希望它包含所有内容: (当使用Microsoft Visual Studio 2013运行时,我得到相同的错误)
// apply_test.cpp : Defines the entry point for the console application.
//
#include <iostream>
#include <boost/noncopyable.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/tuple/tuple.hpp>
using namespace boost;
/* apply methods from https://stackoverflow.com/questions/687490/how-do-i-expand-a-tuple-into-variadic-template-functions-arguments#answer-6454211 */
// ------------- UTILITY---------------
template<int...> struct index_tuple{};
template<int I, typename IndexTuple, typename... Types>
struct make_indexes_impl;
template<int I, int... Indexes, typename T, typename ... Types>
struct make_indexes_impl<I, index_tuple<Indexes...>, T, Types...>
{
typedef typename make_indexes_impl<I + 1, index_tuple<Indexes..., I>, Types...>::type type;
};
template<int I, int... Indexes>
struct make_indexes_impl<I, index_tuple<Indexes...> >
{
typedef index_tuple<Indexes...> type;
};
template<typename ... Types>
struct make_indexes : make_indexes_impl<0, index_tuple<>, Types...>
{};
// ----------UNPACK TUPLE AND APPLY TO FUNCTION ---------
template<class Ret, class... Args, int... Indexes >
Ret apply_helper(Ret(*pf)(Args...), index_tuple< Indexes... >, tuple<Args...>&& tup)
{
return pf(forward<Args>(get<Indexes>(tup))...);
}
template<class Ret, class ... Args>
Ret apply(Ret(*pf)(Args...), const tuple<Args...>& tup)
{
return apply_helper(pf, typename make_indexes<Args...>::type(),
tuple<Args...>(tup));
}
template<class Ret, class ... Args>
Ret apply(Ret(*pf)(Args...), tuple<Args...>&& tup)
{
return apply_helper<Ret, Args...>(pf, typename make_indexes<Args...>::type(), forward<tuple<Args...>>(tup));
}
/* end of apply methods */
/* class iSelectable */
template <typename...> struct iSelectable;
template<class...Ts>
class iSelectable
{
public:
template<typename T>
static T select(Ts&&...params)
{
return T(std::forward<Ts>(params)...);
}
};
/* selector_helper */
template<typename TT, class...Ts>
struct selector_helper
{
static TT doSelect(Ts&&... params)
{
return iSelectable<Ts...>::select<TT>(std::forward<Ts>(params)...);
}
};
class postgres_database_impl : private boost::noncopyable
, public boost::enable_shared_from_this<postgres_database_impl>
{
public:
template<typename T, typename...Ts>
T select_(const std::string& sql)
{
boost::tuple<Ts...> tpl;
/* This is where my errors occur: */
return apply(selector_helper<T, Ts...>::doSelect, tpl);
}
};
typedef boost::shared_ptr<postgres_database_impl> DatabaseImpl;
class Database : private boost::noncopyable
{
public:
template<typename T, typename...Ts>
T select_(const std::string& sql)
{
return impl_->select_<T, Ts...>(sql);
}
private:
DatabaseImpl impl_;
};
class User : public iSelectable < int, std::string, std::string >
{
public:
User(int id, const std::string& name, const std::string& surname)
{
/* only for testing purposes */
std::cout << name << ", ";
std::cout << name << ", ";
std::cout << surname << std::endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Database db;
User result = db.select_<User, int, std::string, std::string>
("select id, email, name from credentials_tbl limit 1");
return 0;
}
答案 0 :(得分:3)
无论问题的背景如何,我通常都希望selector_helper
类型看起来更像:
template <typename...> struct iSelectable;
template<typename TT>
struct selector_helper
{
template<class... Ts>
static TT doSelect(Ts&&... params) {
return iSelectable<Ts...>::template select<TT>(std::forward<Ts>(params)...);
}
};
请注意嵌套template
模板的额外select
限定条件。如果select
是一种类型(我们怎么知道),您可能也需要typename
:Where and why do I have to put the "template" and "typename" keywords?
<强>更新强>
查看更完整的示例,这正是问题所在。 do_select
的模板参数是明确指定的:
return apply(selector_helper<T, Ts...>::doSelect, tpl);
这不会起作用,因为它会抑制模板参数推断,并且签名被强制
User (&)(int&&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&&)
当然,虽然元组实际上是
boost::tuples::tuple<int, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, ...>&
您可以看到针对Args...
推断出的冲突类型。
我实际上会通过不那么具体来简化这个:
template <class Ret, class Tuple, class... Args, int... Indexes>
Ret apply_helper(Ret (*pf)(Args...), index_tuple<Indexes...>, Tuple&& tup) {
return pf(std::forward<Args>(get<Indexes>(std::forward<Tuple>(tup)))...);
}
template <class Ret, class Tuple, class... Args>
Ret apply(Ret (*pf)(Args...), Tuple&& tup) {
return apply_helper(pf, typename make_indexes<Args...>::type(), std::forward<Tuple>(tup));
}
这已编译
<强> Live On Coliru 强>
// apply_test.cpp : Defines the entry point for the console application.
//
#include <iostream>
#include <boost/noncopyable.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/make_shared.hpp>
#define _TCHAR char
using namespace boost;
/* apply methods from
* https://stackoverflow.com/questions/687490/how-do-i-expand-a-tuple-into-variadic-template-functions-arguments#answer-6454211
*/
// ------------- UTILITY---------------
template <int...> struct index_tuple {};
template <int I, typename IndexTuple, typename... Types> struct make_indexes_impl;
template <int I, int... Indexes, typename T, typename... Types>
struct make_indexes_impl<I, index_tuple<Indexes...>, T, Types...> {
typedef typename make_indexes_impl<I + 1, index_tuple<Indexes..., I>, Types...>::type type;
};
template <int I, int... Indexes> struct make_indexes_impl<I, index_tuple<Indexes...> > {
typedef index_tuple<Indexes...> type;
};
template <typename... Types> struct make_indexes : make_indexes_impl<0, index_tuple<>, Types...> {};
// ----------UNPACK TUPLE AND APPLY TO FUNCTION ---------
template <class Ret, class Tuple, class... Args, int... Indexes>
Ret apply_helper(Ret (*pf)(Args...), index_tuple<Indexes...>, Tuple&& tup) {
return pf(std::forward<Args>(get<Indexes>(std::forward<Tuple>(tup)))...);
}
template <class Ret, class Tuple, class... Args>
Ret apply(Ret (*pf)(Args...), Tuple&& tup) {
return apply_helper(pf, typename make_indexes<Args...>::type(), std::forward<Tuple>(tup));
}
/* end of apply methods */
/* class iSelectable */
template <typename...> struct iSelectable;
template <class... Ts> struct iSelectable {
template <typename T> static T select(Ts &&... params) { return T(std::forward<Ts>(params)...); }
};
/* selector_helper */
template <typename TT, class... Ts> struct selector_helper {
static TT doSelect(Ts &&... params) { return iSelectable<Ts...>::template select<TT>(std::forward<Ts>(params)...); }
};
class postgres_database_impl : private boost::noncopyable,
public boost::enable_shared_from_this<postgres_database_impl>
{
public:
template <typename T, typename... Ts> T select_(const std::string &sql) {
boost::tuple<Ts...> tpl { -123, "fame", "something" };
/* This is where my errors occur: */
return apply(selector_helper<T, Ts...>::doSelect, tpl);
return {123, "name", "something"};
}
};
typedef boost::shared_ptr<postgres_database_impl> DatabaseImpl;
class Database : private boost::noncopyable {
public:
template <typename T, typename... Ts> T select_(const std::string &sql) { return impl_->select_<T, Ts...>(sql); }
private:
DatabaseImpl impl_ = boost::make_shared<postgres_database_impl>();
};
class User : public iSelectable<int, std::string, std::string> {
public:
User(int id, std::string name, std::string surname)
: id(id), name(std::move(name)), surname(std::move(surname)) {
}
private:
int id;
std::string name;
std::string surname;
friend std::ostream& operator << (std::ostream& os, User const& user) {
return os << user.id << ", " << user.name << ", " << user.surname << "\n";
}
};
int main() {
Database db;
User result =
db.select_<User, int, std::string, std::string>("select id, email, name from credentials_tbl limit 1");
std::cout << "Result: " << result << "\n";
}
输出:
Result: -123, fame, something
我认为我看到了进一步简化的大量机会,但说实话,我需要了解更多关于开始这一旅程的目标。