The relevant checks on &*ptr are as follows:* Does it perform lvalue-to-rvalue conversion (on an ineligible object)? No, because ptr is constexpr and the lvalue designated by *ptr is not subjected to lvalue-to-rvalue conversion.* Is it UB? No, the unary * is valid as ptr is a pointer to complete object type and points to an object.It's definitely MSVC that is incorrect here.Note also that MSVC is inconsistent in a way, allowing the binding of a constexpr lvalue reference to the result of unary *; it allows us to write:constexpr int& r = *p;static_assert(&r == &i, "!!");I don't know whether this would be of any use to you as a workaround.
#include <type_traits>
int x;
int main()
{
// OK
static_assert(&*&x == &x, "meow");
// OK
static_assert(std::integral_constant<bool, (&*&x == &x)>::value, "kitty");
// GCC errors "template argument 2 is invalid"
static_assert(std::integral_constant<bool, &*&x == &x>::value, "purr");
return 0;
}
template<bool B> struct S {};
int x;
constexpr struct Y { constexpr Y() {} bool const B = true; } y;
S<&y ->* (&Y::B)> a; // gcc: error: template argument 1 is invalid
S<&x == nullptr> b; // same
S<&x && false> c; // same
S<&x ? false : true> d; // same
template<bool B> struct S {};
struct Y {
constexpr Y() {}
constexpr bool operator=(int) const { return false; }
};
struct W {
constexpr W() {}
constexpr Y operator&() const { return {}; }
};
constexpr W w;
S<&w = 0> a; // clang: error: expected '>'
template<bool B> struct S {};
struct Y {
constexpr Y() {}
constexpr Y const& operator+=(int) const { return *this; }
constexpr operator bool() const { return true; }
};
S<Y{} += 1> s; // error: expected '>'
Ah, my bad: an assignment-expression is not a converted constant expression, so clang is perfectly correct:
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussio...@isocpp.org.
To post to this group, send email to std-dis...@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-discussion/.
Excellent! The problem seems to be that gcc gets confused by an unparenthesized address-of expression as the first operand of any operator where that operator-expression is the argument of a non-type template parameter. Some reduced examples:template<bool B> struct S {};
int x;
constexpr struct Y { constexpr Y() {} bool const B = true; } y;
S<&y ->* (&Y::B)> a; // gcc: error: template argument 1 is invalid
S<&x == nullptr> b; // same
S<&x && false> c; // same
S<&x ? false : true> d; // sameI'm guessing there must be something odd in gcc's handling of the address-of operator as I can't provoke it with any other unary operator (note that this can also be provoked using the "bitand" spelling). It happens with every binary and ternary operator that has lower precedence than "&" and can appear inside <> without parentheses.