MSVC无法根据模板参数进行数学运算,这是一个错误吗?

时间:2018-10-03 20:02:10

标签: c++ templates visual-c++

如果不把这个问题弄得太长,我找不到一个非常合适的标题,这就是为什么它可能不太准确的原因。我有一个clamped_value类,它存储一个值并确保该值保持在编译时已知的范围内。现在我正在使用此类:

class SomeClass
{
    using value_type = int;
    using percent_type = clamped_value<value_type, 0, 100>;
};

一切正常,我继续向Precision添加一个SomeClass模板参数

template<int Precision>
class SomeClass
{
    using value_type = int;
    using percent_type = clamped_value<value_type, 0, 100 * (Precision + 1)>;
};

突然,代码中断了!在clamped_value.hpp中已经定义了很多错误,这些错误已经确定了(我确定头保护符在这里是正确的)。我决定使用Gcc(see coliru example here)测试代码,并且效果很好。用Clang编译也可以。这是MSVC中的错误吗?

MSVC版本为15.7.2。

更新

我创建了一个小示例来对自己的行为进行建模,问题消失了:

template<class T, int N, int M>
class clamped_value
{
public:
#define GEN_F(f) void f() {}

    GEN_F(a)
    GEN_F(b)
};

template<int N = 0>
class SomeClass
{
    using percent_type = clamped_value<int, 0, 100 * N>;

public:
    SomeClass()
    {
        percent_type p;
        p.a();
    }
};



int main()
{
    SomeClass<> a;
}

大肠菌链接:https://coliru.stacked-crooked.com/a/a2d612a292e72198

新更新:将VS更新到最新版本无法解决该问题。现在制作更好的MCVE。

1 个答案:

答案 0 :(得分:0)

经过更多工作,我终于发现了问题所在。首先,我设法在gcc here上复制错误。当开始对此进行更多思考时,我终于发现了它。在clamped_value中,有一个宏:

#define GEN_ARITHMETIC_OP(op) \
template<typename Ty, Ty TMin, Ty TMax, typename U, U UMin, U UMax> \
friend constexpr detail::common_clamped_value_t<Ty, TMin, TMax, U, UMin, UMax> \
operator op(clamped_value<Ty, TMin, TMax> const& lhs, clamped_value<U, UMin, UMax> const& rhs) \
{ \
    auto val = detail::common_clamped_value_t<Ty, TMin, TMax, U, UMin, UMax>(lhs.m_value op rhs.m_value); \
    val.clamp(); \
    return val; \
}

现在,这里的问题是第一个clamped_value是模板化的,因此适用于所有clamped_value。因此,如果我仅实例化一个clamped_value,则一切正常。但是从使用一组新的模板参数的那一刻起,宏再次被扩展 ,并且该运算符被定义了两次。一个简单的解决方法是将宏定义更改为仅适用于当前实例化的类型:

#define GEN_ARITHMETIC_OP(op) \
template<typename U, U UMin, U UMax> \
friend constexpr detail::common_clamped_value_t<T, Min, Max, U, UMin, UMax> \
operator op(clamped_value const& lhs, clamped_value<U, UMin, UMax> const& rhs) \
{ \
    auto val = detail::common_clamped_value_t<T, Min, Max, U, UMin, UMax>(lhs.m_value op rhs.m_value); \
    val.clamp(); \
    return val; \
}