我打算使用MySQL连接器。它们提供访问结果行的功能。一些示例包括getString(1)
,getInt(1)
,getDate(2)
。括号内的数字是关于结果的索引。
因此,我必须使用以下代码来访问此示例行:'John', 'M', 34
string name = row.getString(1);
string sex = row.getString(2);
int age = row.getInt(3);
我想出于各种原因尝试泛型编程(主要是为了好玩)。但令人非常失望的是,即使使用了很多时间,我也无法做到这一点。
我想要的最终结果:
std::tie<name, sex, age> = row.getResult<string, string, int>();
此函数应调用相应的MySQL API。
虽然语法错误,但也可以看到类似于下面的任何答案。
std::tie<name, sex, age> = row.getResult([string, string, int]);
请不要建议使用for循环。让我们尝试一些更通用的东西。功能性的; - )
答案 0 :(得分:1)
这对我有用:
struct Row
{
template <int N, typename ... Args> struct Helper;
template <typename Arg1> struct Helper<1, Arg1>
{
static std::tuple<Arg1> getResult(Row& r)
{
return std::make_tuple(r.getResult<Arg1>(0));
}
};
template <int N, typename Arg1, typename ... Args>
struct Helper<N, Arg1, Args...>
{
static std::tuple <Arg1, Args ...> getResult(Row& r)
{
return std::tuple_cat(std::make_tuple(r.getResult<Arg1>(N-1)),
Helper<N-1, Args...>::getResult(r));
}
};
template <typename Arg> Arg getResult(int index)
{
// This is where the value needs to be extracted from the row.
// It is a dummy implementation for testing purposes.
return Arg{};
}
template <typename ... Args>
std::tuple <Args ...> getResult()
{
return Helper<sizeof...(Args), Args...>::getResult(*this);
}
};
使用示例:
Row r;
auto res1 = r.getResult<std::string>();
auto res2 = r.getResult<int>();
auto res3 = r.getResult<int, double, int>();
auto res4 = r.getResult<int, int, double, double>();
auto res5 = r.getResult<std::string, std::string, int, int, double, double>();
答案 1 :(得分:0)
首先你需要写下这些:
template<class T> T get( MySQLRow const& row, unsigned index);
template<>
int get<int>( MySQLRow const& row, unsigned index) { return connector.GetInt(index); }
// etc
然后,添加一些模板元编程工具:
template<class...>struct types{using type=types;};
以上内容可能会替换为std::tuple<?>*
而不是types<?>
。也许。但无论如何,上述情况更加清晰。
接下来,可以用C ++ 14的integral_sequence
:
template<unsigned...>struct indexes{using type=indexes;};
template<unsigned max, unsigned...is>struct make_indexes<max-1, max-1, is...>{};
template<unsigned...is>struct make_indexes<0,is...>:indexes<is...>{};
template<unsigned max>using make_indexes_t=typename make_indexes<max>::type;
最后,东西:
namespace details {
template<unsigned... Is, class... Types>
std::tuple< Types... >
getResult( indexes<Is...>, types<Types...>, MySQLRow const& row ) {
return { get<Types>( row, Is+1 )... };
}
}
template<class... Types>
std::tuple<Types...>
getResult( MySQLRow const& row ) {
return details::getResult( make_indexes_t<sizeof...(Ts)>{}, types<Types...>{}, row );
}
语法是:
getResult<int, double, std::string>( row );
假设您编写了各种get
函数并将MySQLRow
的类型固定为它的实际内容,并假设第一行为1
。
答案 2 :(得分:0)
创建一组函数Get
重载,实现行GetX
方法的统一接口:
#define DEFINE_GET_FOR_TYPE(Type, TypeName) \
void Get(Type& arg, const MySQLRow& row, std::size_t index) \
{ \
arg = row.Get##TypeName(index); \
}
DEFINE_GET_FOR_TYPE(int, Int)
DEFINE_GET_FOR_TYPE(std::string, String)
// ...
此处宏DEFINE_GET_FOR_TYPE
用于创建必要的集合。
使用C ++ 14 GetResult
和std::index_sequence
(they can be implemented in C++11 program, too)实施std::make_index_sequence
功能模板:
struct Iterate
{
Iterate(...) {}
};
template <std::size_t... indices, typename... Types>
void GetResultImpl(const MySQLRow& row, std::index_sequence<indices...>, Types&... args)
{
Iterate{(Get(args, row, indices + 1), 0)...};
}
template <typename... Types>
void GetResult(const MySQLRow& row, Types&... args)
{
GetResultImpl(row, std::make_index_sequence<sizeof...(Types)>(), args...);
}
使用GetResult
函数模板从行中获取值:
std::string name;
std::string sex;
int age;
GetResult(row, name, sex, age);