【问题标题】:How do I create a templated template specialization of a function in c++/c++20?如何在 c++/c++20 中创建函数的模板化模板特化?
【发布时间】:2021-05-29 19:01:54
【问题描述】:

我编写了自己的定点数值类,打算像floatdouble 一样使用:

template<typename T, unsigned Precision> struct fixed {...}

T 必须是 int8_tint16_t、int32_tint64_t,它将使用 Precision 位作为小数部分。没有指数部分。我已经实现了必要的运算符、转换运算符等,一切都按预期工作。

现在我想将这个类与 boost qvm 一起使用并创建我的固定类的 3 维向量:

using fixed_vec3 = boost::qvm::vec<fixed<int32_t, 10>, 3>;
auto my_vec3 = fixed_vec3{1.25, 2.5, 3.75};

到目前为止,一切都很好。但是如果我尝试获取向量的大小,我会遇到一个小问题:

auto my_mag = mag(my_vec3);

显然会产生链接器错误,我缺少在命名空间 boost::qvm 中定义并由 boost::qvm 中的 mag(...) 方法使用的 sqrt 方法特化:

namespace boost::qvm {
...
    template <class T> T sqrt( T );
...
    template <> BOOST_QVM_INLINE_TRIVIAL float sqrt<float>( float x ) { return ::sqrtf(x); }
...
    template <> BOOST_QVM_INLINE_TRIVIAL double sqrt<double>( double x ) { return ::sqrt(x); }
...
}

我有自己的 sqrt 实现:

template<typename T, unsigned Precision>
fixed<T, Precision> sqrt(fixed<T, Precision> val)
{
    return ...;
}

如何为我的模板化 fixed 类创建 boost::qvm::sqrt 的专业化?以下内容已经非常适合fixed 的特定专业化:

namespace ::boost::qvm {
template<>
inline fixed<int32_t, 10>
sqrt<fixed<int32_t, 10>>(fixed<int32_t, 10> value)
{
  return ...
}
}

注意:在boost::qvm中的mag方法内部,方法sqrt是这样调用的:

...
    T const m2=a0*a0+a1*a1+a2*a2;
    T const mag=sqrt<T>(m2);
    return mag;
...

但是,我当然想为所有可能的fixed 模板创建一个模板版本,而不是为fixed&lt;int32_t, 10&gt; 分别创建一个模板版本。枚举它们。重载当然不起作用,因为使用一个参数显式引用了模板。在这种情况下这甚至可能吗?我该怎么做(当然不改变 boost 源代码)?

顺便说一句:我正在使用 Microsoft C++ 编译器 Visual Studio 2019,分别使用 C++ 20。 “最新的工作草案 c++”。

【问题讨论】:

  • 它不能解决你的问题,但是 Boost 不应该提供那个显式的模板参数——而且它应该通过一个可以处理部分特化的类模板进行转发。

标签: c++ templates boost c++20


【解决方案1】:

使用 c++20 可以做到这一点。考虑以下模板函数my_sqrt

template<class T>
T my_sqrt(T x);

完全专业化很简单(例如双重)。

template<>
double my_sqrt(double x) { return sqrt(x); }

可以使用限制类型的requires 子句来实现部分特化(例如,对于任何 std::pair)。

template<class T>
requires is_same_template_v<T, std::pair>
T my_sqrt(T p) {
    return std::make_pair(sqrt(p.first), sqrt(p.second));
}

is_same_template_v 确定类型是否是给定模板的实现:

template<class T, class U, template<class...> class V>
struct is_same_template : std::false_type
{ static constexpr bool value = false; };

template<template<class...> class T, template<class...> class U, class... Ts>
struct is_same_template<T<Ts...>, U<Ts...>, U>
{
    using type = std::true_type;
    static constexpr bool value = std::is_same_v<T<Ts...>,U<Ts...>>;
};

template<class T, template<class...> class U>
using is_same_template_t = typename is_same_template<T,T,U>::type;

/**
 * @brief Is class T a realization of template U?
 *
 * @tparam T the class to test
 * @tparam U the template to compare
 */
template<class T, template<class...> class U>
static constexpr bool is_same_template_v = is_same_template<T,T,U>::value;

对于您的用例,我认为代码如下所示:

namespace ::boost::qvm {
template<class T>
requires is_same_template_v<T, fixed>
T sqrt(T value)
{
  return ...
}
}

免责声明:我使用的是 clang-11,无法访问 VS。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-09
    • 2011-06-27
    • 1970-01-01
    • 2022-07-05
    • 2011-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多