如何在c++/c++20中创建函数的模板化模板特化?



我已经写了我自己的定点数字类,打算像floatdouble那样使用:

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

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

现在我想使用这个类与boost qvm和创建我的固定类的三维向量:

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

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

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::qvmmag方法中,sqrt方法是这样调用的:

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

然而,我当然想为所有可能的fixed模板创建一个模板版本,而不是fixed<int32_t, 10>模板。把它们都列举出来。当然,重载不起作用,因为对模板的显式引用只有一个参数。在这种情况下,这可能吗?我如何做到这一点(当然不改变boost源代码)?

顺便说一句:我正在使用Visual Studio 2019,微软c++编译器,使用c++ 20 resp。最新工作草案c++"

这在c++20中是可能的。考虑下面的模板函数my_sqrt

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

完全专门化是直接的(例如对于double)。

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.

最新更新