我已经写了我自己的定点数字类,打算像float
或double
那样使用:
template<typename T, unsigned Precision> struct fixed {...}
T
必须是int8_t
,int16_
t,int32_t
或int64_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::qvm
的mag
方法中,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.