Broken static_assert in gsl::not_null
Leedehai opened this issue · comments
static_assert(std::is_convertible<decltype(std::declval<T>() != nullptr), bool>::value,
"T cannot be compared to nullptr.");
Please see https://stackoverflow.com/a/65867132/8385554.
Could you please provide an example that shows that the static_assert
is broken?
Addressing the answer in the StackOverflow post:
#include <type_traits>
template<typename T>
void foo()
{
static_assert(
std::is_convertible<decltype(std::declval<T>() != nullptr), bool>::value,
"T cannot be compared to nullptr.");
}
int main()
{
foo<int>();
}
gsl::not_null
is designed to work on pointers. However, the example provided on StackOverflow has a function foo
that takes an int
as the template parameter rather than an int*
, which fails the static_assert
.
@JordanMaples As written in the answer:
This results in a compiler diagnostic, and not an assertion, using Microsoft's own compiler:
So the code is correct in the sense that it prevents gsl::not_null<int>
to compile. But it is broken in the sense that not the static_assert
triggers, but a compiler diagnostic is issued. We would get a better compiler warning with this code:
#include <type_traits>
template<typename T, typename = void>
struct is_nullptr_convertible : std::false_type {};
template <typename T>
struct is_nullptr_convertible<T, std::is_convertible<decltype(std::declval<T>() != nullptr), bool>> : std::true_type {};
template<typename T>
void foo()
{
static_assert(
is_nullptr_convertible<T>::value,
"T cannot be compared to nullptr.");
}
int main()
{
foo<int>();
}
So maybe we could adjust the static_assert
!?
Ah, I understand now. I focused on the wrong part of the answer. I thought they were talking about consumption of the type rather than the source of the error. I'm going to blame a lack of coffee.
Would you mind drafting a PR so I can discuss it with the other maintainers this week?
PR #975
@CaseyCarter or @StephanTLavavej, would one of you mind looking at this static_assert
from gsl::not_null
?
As it currently exists:
static_assert(std::is_convertible<decltype(std::declval<T>() != nullptr), bool>::value,
"T cannot be compared to nullptr.");
Do you have any suggestions as to how we can revise this so that the static_assert
fires, rather than the compiler diagnostic?
You'll need to make a "comparable to nullptr
" trait and static_assert
that. Something like:
template <class T, class = void>
constexpr bool meow = false;
template <class T>
constexpr bool meow<T, std::void_t<decltype(std::declval<T>() != nullptr)>> =
std::is_convertible_v<decltype(std::declval<T>() != nullptr), bool>;
static_assert(meow<T>, "Bonehead user, T can't be compared to nullptr!");
@CaseyCarter That looks quite similar to what I tried and what worked on my local PC. Do you have an idea why it fails in the CI (see PR #975)?
@CaseyCarter That looks quite similar to what I tried and what worked on my local PC. Do you have an idea why it fails in the CI (see PR #975)?
I left a comment on the PR.