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

Posted

技术标签:

【中文标题】MSVC 无法根据模板参数进行数学运算,这是一个错误吗?【英文标题】:MSVC fails to do math dependent on template parameters, is this a bug? 【发布时间】:2018-10-03 20:02:09 【问题描述】:

如果不把它弄得太长,我找不到一个非常合适的标题,所以这可能不是很准确。我有一个类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。

【问题讨论】:

你能在这里发minimal reproducible example吗?您的链接中有很多不需要的代码,并且不包括您的SomeClass 是的,当然。忘记了。 @MivVG 这是 MSVC 中的错误吗? -- 版本?应用了更新和服务包? @MivVG 你能添加一个代码不起作用的例子吗? 我正在尝试,但我似乎找不到任何东西,这使得它更加奇怪。在将数学添加到 typedef 之前,我 100% 确定代码可以正常工作 【参考方案1】:

经过更多的工作,我终于发现了问题所在。首先,我设法在 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; \

【讨论】:

以上是关于MSVC 无法根据模板参数进行数学运算,这是一个错误吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 django 模板中进行数学运算? [复制]

MSVC2015 更新 3 可变参数模板解决方法

如果我的模板类型首先作为 lambda 参数出现,MSVC 会引发一个奇怪的错误

在 MSVC 中使用数据成员指针作为模板参数

将模板参数传递给 MSVC 中的宏

无法在 Cloudformation 模板中定义 Cloudwatch 警报的数学表达式