【问题标题】:How do I specialize several type on the same template function?如何在同一个模板函数上专门化几种类型?
【发布时间】:2019-08-07 11:45:26
【问题描述】:

我有一个通用函数来从我的数据库中读取列。它在头文件中的原型是:

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

floatdouble 调用 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));
}

【问题讨论】:

  • 你应该看看 SFINAE

标签: c++ function templates c++17 template-specialization


【解决方案1】:

如果您可以访问,则可以在if constexpr的帮助下将这些专业化组合成一个函数。

类型特征:

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");
}

【讨论】:

  • 您好,感谢您的帮助。我在 ccp 文件中尝试了您的代码,然后在头文件中尝试了您的代码。在这两种情况下我都遇到了同样的错误:undefined reference to void sqlite3_column_template&lt;int&gt;(sqlite3_stmt*, int, int&amp;)' 以及其他类型(long long、const char*、double、unsigned int)
  • 是的,cpp 文件中没有更多模板。我收到与第一条消息相同的错误:未定义对void sqlite3_column_template&lt;long long&gt;(sqlite3_stmt*, int, long long&amp;) 的引用
  • 好的,我的工具链和源文件有问题......现在一切都编译好了,但是导致这个错误error: static assertion failed: wrong type 的 static_assert。我将使用我的帖子中发布的解决方案。谢谢你的帮助
【解决方案2】:

您可以使用std::enable_if 根据使用SFINAE 的类型特征有条件地从重载决议中删除函数。

使用 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));
}

【讨论】:

  • 我认为您的示例无法编译。 std::string 专业化匹配什么?
  • @BiagioFesta 对不起,这是一个超载而不是专业化。
  • 是的,现在很好! :)
  • 您好,感谢您的帮助。我在 ccp 文件中尝试了您的代码,然后在头文件中尝试了您的代码。在这两种情况下我都遇到了同样的错误:undefined reference to void sqlite3_column_template(sqlite3_stmt*, int, int&)'` 以及其他类型(long long, const char*, double, unsigned int)
  • 如果头文件被调用一次,您的解决方案就可以工作。否则 std::string 的函数会被多次定义:multiple definition of sqlite3_column_template(sqlite3_stmt*, int, std::__cxx11::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;&amp;)。我使用了一些@Jejo 代码来解决这个问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多