I want to simplify a code by using a constexpr
function instead of multi constexpr
if
branches.
This is the code with the old code commented
the old code compiles with msvc
(vs 2017 with c++17
) and clang
(android ndk r20
), but it fails to compile with clang 8
in for windows x64
in visual studio
!
and the new code neither compiles with msvc
nor 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;
The new code fails to compile in this line :
if constexpr (!IsValueNegative(null_value)) // SOCKET invalid handle is -1
the error code from msvc is :
Error C2131 expression did not evaluate to a constant
and from clang 8 :
constexpr if condition is not a constant expression
however all the null_value is known at compile time
Clang gives this error when you run it:
note: cast that performs the conversions of a reinterpret_cast is not allowed in a constant expression
return (intptr_t)value < 0;
Casting a pointer to an integer type is not a constant expression (because it is a reinterpret_cast
), so you can't use if constexpr
.