基于模板参数类型具有两种不同类型的条件运算符

Conditional operator with two different types based on type of template parameter

提问人:intrigued_66 提问时间:11/9/2023 更新时间:11/9/2023 访问量:70

问:

我有一个执行数值计算的函数。在一个地方,它处理双精度,在第二个地方,它处理自定义算术类型。因此,该函数是以算术类型为模板的:

template<class T>
T calc(const T input_1)
{
    
}

如果函数是模板化的,我需要转换为 ,否则如果模板类型是 应该保留。doubleinput_2doubleMyNumberinput_2

我用条件运算符尝试过:

template<class T>
T calc(const T input_1)
{
    const MyNumber input_2 = getFromElsewhere();
    const T value = std::is_same_v<double, T> ? input_2.toDouble() : input_2;
    return value + input_1; // example
}

但是,上面的内容无法编译,因为两个CMOV“分支”是不同的类型( vs )。doubleMyNumber

我用静态的if-else替换了条件:

template<class T>
T calc(const T input_1)
{
    const MyNumber input_2 = getFromElsewhere();
    T value;

    if constexpr(std::is_same_v<double, T>)
    {
        value = input_2.toDouble();
    }
    else
    {
        value = input_2;
    }

    return value + input_1; // example
}

但我不喜欢从中删除.constconst T value

有没有一种解决方案,我可以根据 的类型和 keep 切换输入源?Tconst T value

C++ 模板

评论

0赞 463035818_is_not_an_ai 11/9/2023
什么?如果有从条件到条件的转换应该没问题 godbolt.org/z/recTM1jqo。如果没有转换,我看不出它是如何工作的。请发布一个最小的可重复示例MyNumberdoubleMyNumberif else
2赞 463035818_is_not_an_ai 11/9/2023
“但我不喜欢从 const T 值中删除 const。” 您可以使用立即调用的 lambda 表达式
0赞 intrigued_66 11/9/2023
@463035818_is_not_an_ai 是一个十进制类型,但它没有接受双精度的构造函数(因为这变得很棘手)。不过,它确实转换为。MyNumberdouble
0赞 ChrisMM 11/9/2023
const T value = [&]() { ... }();并将 if 语句替换为 if 语句...

答:

1赞 Ahmed AEK 11/9/2023 #1

您可以调用专用于 double 的模板化函数。

template<class T>
T inline unsafeConvert(const MyNumber& input_2)
{
    return input_2;
}

template<>
double inline unsafeConvert(const MyNumber& input_2)
{
    return input_2.toDouble();
}

template<class T>
T calc(const T input_1)
{
    const MyNumber input_2 = getFromElsewhere();
    const T value = unsafeConvert<T>(input_2);
    return value + input_1; // example
}

或者,您可以让模板化的转换函数包含 而不是定义专用化if constexpr

template<class T>
T inline unsafeConvert(const MyNumber& input_2)
{
    if constexpr(std::is_same_v<double, T>)
    {
        return input_2.toDouble();
    }
    else
    {
        return input_2;
    }
}

463035818_is_not_an_ai在注释中指出的另一个选项是立即调用的 Lambda。

template<class T>
T calc(const T input_1)
{
    const MyNumber input_2 = getFromElsewhere();
    const T value = [&](){
    if constexpr(std::is_same_v<double, T>)
    {
        return input_2.toDouble();
    }
    else
    {
        return input_2;
    }
    }();

    return value + input_1; // example
}

如果您唯一的特殊情况是 double,并且您正在使用此函数一次,则应立即使用此函数,但如果您经常重用此函数,那么您可能应该使用模板函数路由。

1赞 Ted Lyngmo 11/9/2023 #2

您可以通过将 convertible 转换为 来简化它,这意味着如果您愿意,可以删除成员函数:MyNumberdoubletoDouble()

class MyNumber {
public:
    //...
    explicit operator double() const { return m_value; }
    //...    
};

然后,will 的实现不需要任何特殊性,除了 ,如果 是,它将不执行任何操作,否则使用转换运算符。calcstatic_castTMyNumber

template <class T>
T calc(const T input_1) {
    const T value = static_cast<T>(getFromElsewhere());

    return value + input_1;  // example
}

如果既不是也不是,则不会编译,就像调用缺少该成员函数的类型(或非类型)一样。TdoubleMyNumbertoDouble()

但是,您可以为 etc 添加更多重载,而无需更改 。然后会选择正确的一个,所以不需要等。explicit operator type () constfloatMyNumbercalcstatic_cast<T>toFloat()