如何在同一个模板函数上专门化多个类型?
How do I specialize several type on the same template function?
我有一个通用函数可以从我的数据库中读取列。它在头文件中的原型是:
template <typename T> void sqlite3_column_template(sqlite3_stmt *stmt, int column, T& value);
想法是根据值类型专门化此函数来调用这些函数:
sqlite3_column_int64(...)
sqlite3_column_double(...)
sqlite3_column_text(...)
在我的 cpp
文件中,我编写了这样的专业化函数:
template <> void sqlite3_column_template(sqlite3_stmt *stmt, int column, int& value)
{
value = sqlite3_column_int64(stmt, column);
}
template <> void sqlite3_column_template(sqlite3_stmt *stmt, int column, float& value)
{
value = sqlite3_column_double(stmt, column);
}
template <> void sqlite3_column_template(sqlite3_stmt *stmt, int column, std::string& value)
{
value = reinterpret_cast<const char*>(sqlite3_column_text(stmt, column));
}
我遇到的问题是调用此函数时的值类型可以是以下类型:
uint32_t, int32_t, int64_t
float, double
我不知道如何判断所有“整数”类型都必须调用函数sqlite3_column_int64
。
float
和 double
相同,调用 sqlite3_column_double
函数。
我该怎么做?有可能吗?
编辑
我使用的解决方案如下:
// the 3 functions in the header file
template <typename T>
std::enable_if_t<std::is_integral_v<T>> sqlite3_column_template(sqlite3_stmt *stmt, int column, T& value)
{
value = sqlite3_column_int64(stmt, column);
}
template <typename T>
std::enable_if_t<std::is_floating_point_v<T>> sqlite3_column_template(sqlite3_stmt *stmt, int column, T& value)
{
value = sqlite3_column_double(stmt, column);
}
template <typename T>
std::enable_if_t<std::is_same_v<T, std::string>> sqlite3_column_template(sqlite3_stmt *stmt, int column, T& value)
{
value = reinterpret_cast<const char*>(sqlite3_column_text(stmt, column));
}
您可以使用 std::enable_if
to conditionally remove functions from overload resolution based on type traits using SFINAE.
std::is_integral<T>
检查 T 是否为整数类型。
std::is_floating_point<T>
检查 T 是否为浮点类型。
使用 enable_if 后的代码:
template <typename T>
std::enable_if_t<std::is_integral_v<T>> sqlite3_column_template(sqlite3_stmt *stmt, int column, T& value)
{
value = sqlite3_column_int64(stmt, column);
}
template <typename T>
std::enable_if_t<std::is_floating_point_v<T>> sqlite3_column_template(sqlite3_stmt *stmt, int column, T& value)
{
value = sqlite3_column_double(stmt, column);
}
void sqlite3_column_template(sqlite3_stmt *stmt, int column, std::string& value)
{
value = reinterpret_cast<const char*>(sqlite3_column_text(stmt, column));
}
如果您有权访问 c++17, you could combine the specializations to one single function with the help of if constexpr.
其中类型特征:
std::is_integral
已用于检查类型是否为整数。
std::is_floating_point
已用于检查类型是否为浮点数。
std::is_same_v<T, U>
已被使用
检查类型(即 T
和 U
)是否相同(用于检查
std::string
).
sqlite3_column_template
现在可以写成:
#include <type_traits> // std::is_integral, std::is_floating_point, std::is_same
template <typename T>
void sqlite3_column_template(sqlite3_stmt *stmt, int column, T& value)
{
if constexpr (std::is_integral_v<T>)
{
value = sqlite3_column_int64();
// do something more
}
else if constexpr (std::is_floating_point_v<T>)
{
value = sqlite3_column_double();
// do something more
}
else if constexpr (std::is_same_v<T, std::string>)
{
value = sqlite3_column_text();
// do something more
}
else
static_assert(false, "wrong type");
}
我有一个通用函数可以从我的数据库中读取列。它在头文件中的原型是:
template <typename T> void sqlite3_column_template(sqlite3_stmt *stmt, int column, T& value);
想法是根据值类型专门化此函数来调用这些函数:
sqlite3_column_int64(...)
sqlite3_column_double(...)
sqlite3_column_text(...)
在我的 cpp
文件中,我编写了这样的专业化函数:
template <> void sqlite3_column_template(sqlite3_stmt *stmt, int column, int& value)
{
value = sqlite3_column_int64(stmt, column);
}
template <> void sqlite3_column_template(sqlite3_stmt *stmt, int column, float& value)
{
value = sqlite3_column_double(stmt, column);
}
template <> void sqlite3_column_template(sqlite3_stmt *stmt, int column, std::string& value)
{
value = reinterpret_cast<const char*>(sqlite3_column_text(stmt, column));
}
我遇到的问题是调用此函数时的值类型可以是以下类型:
uint32_t, int32_t, int64_t
float, double
我不知道如何判断所有“整数”类型都必须调用函数sqlite3_column_int64
。
float
和 double
相同,调用 sqlite3_column_double
函数。
我该怎么做?有可能吗?
编辑
我使用的解决方案如下:
// the 3 functions in the header file
template <typename T>
std::enable_if_t<std::is_integral_v<T>> sqlite3_column_template(sqlite3_stmt *stmt, int column, T& value)
{
value = sqlite3_column_int64(stmt, column);
}
template <typename T>
std::enable_if_t<std::is_floating_point_v<T>> sqlite3_column_template(sqlite3_stmt *stmt, int column, T& value)
{
value = sqlite3_column_double(stmt, column);
}
template <typename T>
std::enable_if_t<std::is_same_v<T, std::string>> sqlite3_column_template(sqlite3_stmt *stmt, int column, T& value)
{
value = reinterpret_cast<const char*>(sqlite3_column_text(stmt, column));
}
您可以使用 std::enable_if
to conditionally remove functions from overload resolution based on type traits using SFINAE.
std::is_integral<T>
检查 T 是否为整数类型。std::is_floating_point<T>
检查 T 是否为浮点类型。
使用 enable_if 后的代码:
template <typename T>
std::enable_if_t<std::is_integral_v<T>> sqlite3_column_template(sqlite3_stmt *stmt, int column, T& value)
{
value = sqlite3_column_int64(stmt, column);
}
template <typename T>
std::enable_if_t<std::is_floating_point_v<T>> sqlite3_column_template(sqlite3_stmt *stmt, int column, T& value)
{
value = sqlite3_column_double(stmt, column);
}
void sqlite3_column_template(sqlite3_stmt *stmt, int column, std::string& value)
{
value = reinterpret_cast<const char*>(sqlite3_column_text(stmt, column));
}
如果您有权访问 c++17, you could combine the specializations to one single function with the help of if constexpr.
其中类型特征:
std::is_integral
已用于检查类型是否为整数。std::is_floating_point
已用于检查类型是否为浮点数。std::is_same_v<T, U>
已被使用 检查类型(即T
和U
)是否相同(用于检查std::string
).
sqlite3_column_template
现在可以写成:
#include <type_traits> // std::is_integral, std::is_floating_point, std::is_same
template <typename T>
void sqlite3_column_template(sqlite3_stmt *stmt, int column, T& value)
{
if constexpr (std::is_integral_v<T>)
{
value = sqlite3_column_int64();
// do something more
}
else if constexpr (std::is_floating_point_v<T>)
{
value = sqlite3_column_double();
// do something more
}
else if constexpr (std::is_same_v<T, std::string>)
{
value = sqlite3_column_text();
// do something more
}
else
static_assert(false, "wrong type");
}