简体   繁体   English

为什么此代码无法编译?

[英]Why does this code fail to compile?

I know it's a pretty general title, but I have some code and it strikes me as weird that it cant compile. 我知道这是一个相当笼统的标题,但我有一些代码,它无法编译很奇怪。

Here is a demo of the issue. 是该问题的演示。 If you change scalar_t from double to float the code compiles fine. 如果将scalar_tdouble更改为float则代码可以正常编译。 Why cant float be promoted to double here? 为什么不能在这里将浮动货币提高一倍? In fact, if you change the constants to double s ( 1.0 ) or int s ( 1 ) they also cant be promoted. 实际上,如果将常数更改为double s( 1.0 )或int s( 1 ),它们也将无法提升。 Isn't this the kind of thing that should just work? 这不是应该起作用的事情吗?

Full code sample: 完整代码示例:

#include <valarray>
#include <numeric>
#include <iterator>
#include <iostream>

template<typename T>
T sigmoid(const T &in)
{
    return 1.f / (1.f + std::exp(-in));
}

template<typename T>
T logit(const T &in)
{
    return std::log(in / (1.f - in));
}

using scalar_t = double;

int main(int argc, char **argv)
{
    std::valarray<scalar_t> f = { 0.1f, 0.3f, 0.5f, 0.9f };

    scalar_t alpha = 0.5f;
    scalar_t beta = -1.f;

    auto lC = logit(f);    
    std::valarray<scalar_t> skC = alpha * lC + beta;
    auto sC = sigmoid(skC);

    std::copy(std::begin(sC), std::end(sC), std::ostream_iterator<scalar_t>(std::cout, " "));
    std::cout << std::endl;

    scalar_t num = 0.7f;
    auto lS = logit(num);
    auto sS = sigmoid(alpha * lS + beta);

    std::cout << sS << std::endl;

    return 0;
}

The operator - you are using is defined as 您正在使用的operator -定义为

template <class T> std::valarray<T> operator- (const T& val, const std::valarray<T>& rhs);

This meas that it expects val to be the same type as the elements in the valarray . 这意味着它期望valvalarray的元素具有相同的类型。 Since you are using a float when template argument deduction happens it sees that val is a float but rhs has a element type of double . 由于在进行模板参数推导时使用的是float ,因此可以看到valfloatrhs的元素类型为double since these types do not match the deduction fails and you get a compiler error. 由于这些类型不匹配,推论失败,并且您得到编译器错误。 Remember no conversions happen during template argument deduction. 请记住,模板参数推导过程中不会发生任何转换。

This spawned a pretty interesting discussion about how to use constants in these type agnostic templates. 这引发了关于如何在这些类型不可知的模板中使用常量的有趣讨论。 Surprisingly there seems to be an answer. 令人惊讶的是似乎有一个答案。 Examining the sigmoid function, we see that it also uses float constants with a valarray<double> but doesnt exhibit a compiler error. 检查sigmoid函数,我们发现它也使用带有valarray<double> float常量,但没有出现编译器错误。 This is because, the std::exp(-in) line converts the valarray<double> to an expression template used the the standard library to optimize the computation, and for whatever reason it doesn't care about float or double (eg they provide the overload). 这是因为std::exp(-in)行将valarray<double>转换为使用标准库优化计算的表达式模板,并且无论出于何种原因,它都不关心floatdouble (例如,它们提供超载)。 So the solution I came up with was to add a unary + operator to the logit function which does absolutely nothing except convert the valarray<double> to an expression template which can work with the float constant. 因此,我想出的解决方案是在logit函数中添加一元+运算符,该函数除了将valarray<double>转换为可以与float常数一起使用的表达式模板外,什么也不做。

Here is the update code sample 是更新代码示例

and the new logit function looks like this 新的logit函数如下所示

template<typename T>
T logit(const T &in)
{
    return std::log(in / (1.f - (+in)));
}

Note the unary + operator (+in) 注意一元+运算符(+in)

Also note that NathanOliver's accepted solution answers the question as asked 另请注意,NathanOliver接受的解决方案按照要求回答了问题

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM