为什么这个constexpr如果不编译

时间:2019-08-22 13:46:54

标签: c++ c++17 constexpr if-constexpr

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

这是带有旧代码注释的代码 旧代码使用msvc(vs 2017使用c++17)和clangandroid ndk r20)进行编译,但是在{{1 }}在clang 8中!

并且新代码既不能用windows x64也不能用visual studio编译

msvc

新代码无法在此行中编译:

clang

msvc的错误代码是:

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;

和从c 8:

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

但是所有null值在编译时都是已知的

1 个答案:

答案 0 :(得分:4)

运行时,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