I recently asked a question here ( Detecting a constexpr instance method using SFINAE ), where I tried to do some constexpr detection at compile time. In the end, I realized that noexcept can be used for this: any constant expression is also noexcept . So I put together the following technique:
template <class T> constexpr int maybe_noexcept(T && t) { return 0; } ... constexpr bool b = noexcept(maybe_noexcept(int{}));
This works, and b true, as you would expect, since initializing zero to int is a constant expression. It also correctly returns zero when it should (if I change int to some other suitable type).
Next, I wanted to check that something constexpr moving constructively. So I did this:
constexpr bool b = noexcept(maybe_noexcept(int(int{})));
And again, this works correctly for an int or user-defined type. However, this verifies that the type has both a default constexpr constructor and a constexpr move constructor. So, to get around this, I tried switching to declval:
constexpr bool b = noexcept(maybe_noexcept(int(declval<int>())));
This causes b be false in gcc 5.3.0 (cannot use clang for any of this, because clang does noexcept constant expressions noexcept ). Not a problem, I say, it should be because declval (interestingly) is not marked constexpr . Therefore, I am writing my naive version:
template <class T> constexpr T&& constexpr_declval() noexcept;
Yes, this is naive compared to the way the standard library does, as it will sweep the void and possibly other things, but so far it is beautiful. So I will try again:
constexpr bool b = noexcept(maybe_noexcept(int(constexpr_declval<int>())));
This still does not work, b always false. Why is this not considered a constant expression? Is this a compiler error, or do I not understand the fundamental information about constexpr ? There seems to be some kind of weird interaction between constexpr and invaluable contexts.