使用模板来防止缩小范围但允许扩大输入范围

问题描述 投票:0回答:1

我有一个类模板,旨在在浮点上进行模板化。 该类有一个方法,应该允许在需要时扩大输入(例如

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

如何简化实施,以更干净的方式实现既定目标?

编辑:将错误的术语“向上转型”和“向下转型”更改为“加宽”和“缩小”

c++ templates
1个回答
1
投票

您可以通过多种方式做到这一点,例如使用概念:

#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 );
};
© www.soinside.com 2019 - 2024. All rights reserved.