简体   繁体   English

MSVC constexpr函数'xyz'不能导致常量表达式

[英]MSVC constexpr function 'xyz' cannot result in a constant expression

I've made a function that concatenates multiple smaller values into one larger value while preserving the bianry representation of the values (ex. to build an int argb from multiple unsigned char r, g, b, a ). 我已经创建了一个函数,它将多个较小的值连接成一个较大的值,同时保留值的bianry表示(例如,从多个unsigned char r, g, b, a构建一个int argb )。 I know I can also achive this by bit shifting the values but that's not the matter of this question. 我知道我也可以通过改变价值来实现这一点,但这不是这个问题的问题。

However, if I use the function to actually generate an integer from those values, msvc throws a compiler error: 但是,如果我使用该函数实际从这些值生成一个整数,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 ()'

Here is a complete sample. 是一个完整的样本。 Clang and gcc compile the code but msvc refuses: 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));
    }
};

Do clang and gcc just ignore that the code will never run as a constexpr or is msvc wrong? clang和gcc只是忽略代码永远不会作为constexpr运行或msvc错误? And if msvc is correct, why can't the function run at compile time? 如果msvc是正确的,为什么函数不能在编译时运行?

Every compiler is correct. 每个编译器都是正确的 The rule in [dcl.constexpr]/5 is: [dcl.constexpr] / 5中的规则是:

For a constexpr function or constexpr constructor that is neither defaulted nor a template, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression, or, for a constructor, a constant initializer for some object ([basic.start.static]), the program is ill-formed, no diagnostic required. 对于既不是默认也不是模板的constexpr函数或constexpr构造函数,如果不存在参数值,则函数或构造函数的调用可以是核心常量表达式的计算子表达式,或者对于构造函数,可以是常量初始化函数。一些对象([basic.start.static]),程序格式错误,无需诊断。

There is no set of arguments you can pass in to binary_fusion that would allow it to be evaluated as a core constant expression, so declaring it constexpr is ill-formed, NDR. 没有一组参数可以传递给binary_fusion ,这样可以将它作为核心常量表达式进行求值,因此声明constexpr是不正确的NDR。 The reason this is the case is because detail::binary_fusion() initializes a union with one active member and then reads from the inactive member, which you are not allowed to do in constant expressions ( [expr.const]/4.8 ): 这种情况的原因是因为detail::binary_fusion()使用一个活动成员初始化一个union,然后从非活动成员读取,在常量表达式中不允许这样做( [expr.const] /4.8 ):

an lvalue-to-rvalue conversion that is applied to a glvalue that refers to a non-active member of a union or a subobject thereof; 应用于glvalue的左值到右值转换,该glvalue引用联合或其子对象的非活动成员;

MSVC somehow diagnoses this, gcc/clang happen not to. MSVC以某种方式诊断出这一点,gcc / clang不会发生。 All compilers correctly diagnose this: 所有编译器都正确诊断了这个:

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

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

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