我制作了一个函数,可以将多个较小的值连接为一个较大的值,同时保留值的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] 删除。
我来说两句