我有一个类模板,旨在在浮点上进行模板化。 该类有一个方法,应该允许在需要时扩大输入(例如
float
-> double
),但不应允许缩小(即精度损失)。
我将如何执行此操作?
下面的例子是我能做到的最好的例子(使用
if constexpr
,所以至少是 c++17),但我觉得同时使用未实现的专业化和 static_cast
可能不是最好的选择最干净、最清晰的解决方案。
它实际上完成了所描述的工作,只要使用 float
和 double
(而不是更深奥的浮点类型),这对我来说不是问题:
#include <vector>
#include <type_traits>
template <typename Real>
class Foo
{
public:
template <typename Real2>
void DoSomething( const std::vector<Real2>& v );
};
// Enter here only when input is of same type as template
template <typename Real>
template <typename Real2>
void Foo<Real>::DoSomething( const std::vector<Real2>& v)
{
if constexpr ( !std::is_same<Real, Real2>::value )
static_assert(false);
// ... Do actual work here ...
}
// Allow widening of inputs
template <>
template <>
void Foo<double>::DoSomething( const std::vector<float>& v)
{
std::vector<double> v2;
v2.reserve( v.size() );
for ( const auto& val : v )
v2.push_back( (double)val );
DoSomething(v2);
}
// Deny narrowing of inputs
template <>
template <>
void Foo<float>::DoSomething( const std::vector<double>& v);
int main()
{
std::vector<float> v1;
std::vector<double> v2;
// ... populate both v1 & v2 ...
Foo<float> b1;
b1.DoSomething( v1 );
b1.DoSomething( v2 );
Foo<double> b2;
//b2.DoSomething( v1 ); // <--- This line should not be allowed to compile
b2.DoSomething( v2 );
}
如何简化实施,以更干净的方式实现既定目标?
编辑:将错误的术语“向上转型”和“向下转型”更改为“加宽”和“缩小”
您可以通过多种方式做到这一点,例如使用概念:
#include <vector>
template <typename Real>
class Foo
{
public:
template <typename Real2>
requires requires (Real r) {Real2{r};} // <-- here
void DoSomething( const std::vector<Real2>& v );
};
或者,使用命名概念产生更清晰的错误消息:
template <typename A, typename B>
concept is_not_narrower = requires(B b) {A{b};};
template <typename Real>
class Foo
{
public:
template <typename Real2>
requires is_not_narrower<Real2, Real>
void DoSomething( const std::vector<Real2>& v );
};