为什么这个 constexpr if 不编译

why this constexpr if doesn't compile

我想通过使用 constexpr 函数而不是多个 constexpr if 分支来简化代码。

这是旧代码注释掉的代码 旧代码使用 msvc(与 2017 使用 c++17)和 clangandroid ndk r20)编译,但无法使用 clang 8 编译 [=22] =] 在 visual studio !

并且新代码既不使用 msvc 也不使用 clang

进行编译
template <class T>
constexpr bool IsValueNegative(T value) // this function should be evaluated at runtime but it it isn't !
{
    if constexpr (std::is_integral_v<T>) // SOCKET = ULONG_PTR and linux handles are int
    {
        return value < 0;
    }
    else // HANDLE = void * and most other handles are pointers
    {
        return (intptr_t)value < 0;
    }
}

template <class T, const T null_value, bool no_negative = true>
class HandleWrapper
{
public:
    HandleWrapper() : handle(null_value)
    {}
    HandleWrapper(T h) : handle(h)
    {
        if constexpr (no_negative) // to convert INVALID_HANDLE_VALUE to nullptr
        {
            if constexpr (!IsValueNegative(null_value)) // SOCKET invalid handle is -1
            {
                if (IsValueNegative(handle)) // 
                    handle = null_value;
            }
            /*
            if constexpr (std::is_integral_v<T>)
            {
                if constexpr (null_value >= 0)
                {
                    if (handle < 0)
                        handle = null_value;
                }
            }
            else
            {
                if constexpr ((intptr_t)null_value >= 0) // clang 8 can't compile this , don't know why
                {
                    if ((intptr_t)handle < 0)
                        handle = null_value;
                }
            }
            */
        }
    }
private:
    T handle;
};

template <class T, const T null_value, bool no_negative, auto Deleter>
struct HandleHelper
{
    using pointer = HandleWrapper<T, null_value, no_negative>;
    void operator()(pointer p)
    {
        if constexpr (!no_negative)
        {
            if (!IsValueNegative(null_value) && IsValueNegative(T(p))) // pseudo handle from GetCurrentProcess or GetCurrentThread
                return;
        }
        /*
        if constexpr (!no_negative && )
        {
            if ((uintptr_t)T(p) <= 0)
            {
                std::cout << "[*] this is a pseudo handle\n";
                return;
            }
        }
        */
        Deleter(T(p));
    }
};

using Handle = std::unique_ptr<HandleWrapper<HANDLE, nullptr, true>, HandleHelper<HANDLE, nullptr, true, CloseHandle>>;
using ProcessHandle = std::unique_ptr<HandleWrapper<HANDLE, nullptr, false>, HandleHelper<HANDLE, nullptr, false, CloseHandle>>;
using ThreadHandle = ProcessHandle;

新代码在这一行编译失败:

if constexpr (!IsValueNegative(null_value)) // SOCKET invalid handle is -1

msvc 的错误代码是:

Error C2131 expression did not evaluate to a constant

来自 clang 8 :

constexpr if condition is not a constant expression

然而所有 null_value 在编译时都是已知的

Clang 在您 运行 时给出此错误:

note: cast that performs the conversions of a reinterpret_cast is not allowed in a constant expression
        return (intptr_t)value < 0;

将指针转换为整数类型不是常量表达式(因为它是一个reinterpret_cast),所以不能使用if constexpr.