c++ - MSVC constexpr 函数 'xyz' 无法生成常量表达式

标签 c++ visual-c++ c++17

我做了一个函数,将多个较小的值连接成一个较大的值,同时保留值的二进制表示(例如,从多个 unsigned char r 构建一个 int argb, 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 ()'

Here是一个完整的样本。 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中的规则是:

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.

没有一组参数可以传递给 binary_fusion 以允许它被评估为核心常量表达式,因此声明它 constexpr 格式错误, 北路。出现这种情况的原因是因为 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;

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

关于c++ - MSVC constexpr 函数 'xyz' 无法生成常量表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53888313/

相关文章:

特定长度的C++字符串

c++ - 为什么 OnKeyDown 不捕获基于对话框的 MFC 项目中的按键事件?

c++ - 在 C++17 中的每个实例化中生成一个新类型

visual-studio - AVX512 和 MSVC 预处理器符号

c++ - 非冗长的解决方案,使基于模板类型的类成员变量为可选?

c++ - 模板函数无法识别由 auto 变量引用的 lambda

c++ - 将 HTML 源代码读取为字符串

c++ - boost::lexical_cast 的替代方案

c++ - Doxygen C++ 约定

c++ - 与 Boost 错误链接