1

我知道这是一个非常笼统的标题,但我有一些代码,令我感到奇怪的是它无法编译。

是该问题的演示。如果您scalar_t从更改doublefloat代码编译正常。为什么在这里不能将float提升为double?事实上,如果将常量更改为doubles ( 1.0) 或ints ( 1),它们也无法提升。这不是应该起作用的事情吗?

完整代码示例:

#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;
}
4

2 回答 2

4

您正在使用的operator -定义为

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

这意味着它期望valvalarray. 由于您使用的是float模板参数推导发生时,它看到它val是 afloatrhs元素类型为double. 由于这些类型不匹配,因此推导失败并且您会收到编译器错误。请记住,在模板参数推导期间不会发生任何转换。

于 2016-11-02T18:26:20.923 回答
1

这引发了关于如何在这些类型无关模板中使用常量的非常有趣的讨论。令人惊讶的是,似乎有了答案。检查sigmoid函数,我们看到它也使用float带有 a 的常量,valarray<double>但没有出现编译器错误。这是因为,该std::exp(-in)行将 转换为valarray<double>使用标准库优化计算的表达式模板,并且无论出于何种原因它都不关心floatdouble(例如,它们提供重载)。所以我想出的解决方案是在函数中添加一个一元 + 运算符,除了将 转换为可以使用常量的表达式模板logit之外,它什么都不做。valarray<double>float

是更新代码示例

logit功能看起来像这样

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

注意一元 + 运算符(+in)

另请注意,NathanOliver 接受的解决方案按要求回答了问题

于 2016-11-02T22:01:52.703 回答