MSVC constexpr函数“ xyz”无法产生常量表达式

蒂莫

我制作了一个函数,可以将多个较小的值连接为一个较大的值,同时保留值的bianry表示(例如,int argb从多个生成unsigned char r, g, b, a)。我知道我也可以通过将值移位来实现此目的,但这不是这个问题的问题。

但是,如果我使用该函数从这些值实际生成一个整数,则msvc会引发编译器错误:

error C3615: constexpr function 'Color::operator int' cannot result in a constant expression
note: failure was caused by call of undefined function or one not declared 'constexpr'
note: see usage of '<lambda_dcb9c20fcc2050e56c066522a838749d>::operator ()'

是一个完整的示例。Clang和gcc编译代码,但msvc拒绝:

#include <type_traits>
#include <memory>

namespace detail
{
    template <typename From, typename To, size_t Size>
    union binary_fusion_helper
    {
        const From from[Size];
        const To to;
    };

    template <typename To, typename Arg, typename ...Args, typename = std::enable_if_t<(... && std::is_same_v<std::remove_reference_t<Arg>, std::remove_reference_t<Args>>)>>
    constexpr To binary_fusion(Arg arg, Args... args)
    {
        using in_t = std::remove_reference_t<Arg>;
        using out_t = To;
        static_assert(sizeof(out_t) == sizeof(in_t) * (sizeof...(Args) + 1), "The target type must be of exact same size as the sum of all argument types.");
        constexpr size_t num = sizeof(out_t) / sizeof(in_t);
        return binary_fusion_helper<in_t, out_t, num> { std::forward<Arg>(arg), std::forward<Args>(args)... }.to;
    }
}

template <typename To>
constexpr auto binary_fusion = [](auto ...values) -> To
{
    return detail::binary_fusion<std::remove_reference_t<To>>(values...);
};

struct Color
{
    float r, g, b, a;

    explicit constexpr operator int() const noexcept
    {
        return binary_fusion<int>(static_cast<unsigned char>(r * 255), static_cast<unsigned char>(g * 255),
                                  static_cast<unsigned char>(b * 255), static_cast<unsigned char>(a * 255));
    }
};

clang和gcc只是忽略代码永远不会作为constexpr运行还是msvc错误吗?如果msvc是正确的,为什么函数不能在编译时运行?

巴里

每个编译器都是正确的。[dcl.constexpr] / 5中的规则是:

对于既没有默认值也没有模板的constexpr函数或constexpr构造函数,如果不存在任何参数值,使得对该函数或构造函数的调用可以是核心常量表达式的求值子表达式,或者对于构造函数,则为用于某些对象([basic.start.static]),程序格式错误,无需诊断。

没有可传递的参数集可以binary_fusion将其作为核心常量表达式进行评估,因此请声明其constexpr格式错误,即NDR。之所以如此,是因为detail::binary_fusion()用一个活动成员初始化一个联合,然后从该非活动成员中读取,这是不允许在常量表达式([expr.const] /4.8)中进行的:

从左值到右值的转换,该值应用于引用联合的非活动成员或其子对象的glvalue;

MSVC以某种方式诊断出此错误,gcc / clang却没有。所有编译器都可以正确诊断:

constexpr Color c{1.0f, 1.0f, 1.0f, 1.0f};
constexpr int i = static_cast<int>(c); // error: not a constant expression

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

constexpr函数中的for循环无法使用MSVC 19.23进行编译

MSVC无法评估enable_if内部的constexpr函数

MSVC和constexpr函数参数?

为什么用成员数组调用constexpr函数不是常量表达式?

在常量表达式上下文中定义之前,嵌套的constexpr函数调用

constexpr-函数不能在常量表达式中使用

C ++ 11 constexpr函数中的常量表达式字符串参数

在常量表达式中调用的“静态constexpr”函数是...错误?

像C ++ constexpr这样的ANSI-C常量表达式函数?

不需要constexpr函数来返回常量表达式吗?

什么决定constexpr函数是否为常量表达式?

缩小从“ int”(常量表达式)到“ unsigned int”的转换-MSVC vs gcc vs clang

使用constexpr initializer_list构造函数时,MSVC无法编译

Lambda函数中不是常量表达式

获取常量char数组的字符串长度函数(strlen)不是常量表达式

“函数调用必须在常量表达式中具有常量值”

通过引用调用constexpr方法-结果是否为常量表达式?

static_casting constexpr void *是常量表达式的结果吗?

为什么MSVC ++ 11拒绝函数的constexpr限定?

Constexpr函数指针作为模板参数MSVC vs GCC

通过函数构建端点值-注释属性X的值必须为常量表达式

铛说对无效约束函数的调用不是常量表达式

C结构对象堆栈-常量表达式中不允许函数调用(错误)

常量表达式中的模板化委派副本构造函数

常量表达式中带有未初始化成员的“默认”构造函数

函数声明行上的“需要常量表达式”错误

未知值的函数参数不能在常量表达式中使用

intel fortran编译错误“此内在函数在常量表达式中无效”

如何使用boost.hana解决“在常量表达式中不允许读取非constexpr变量'a'”的问题