I have the following code from Ben Deane talk.
#define CX_VALUE(...) [] { \
struct { \
constexpr auto operator()() const noexcept { return __VA_ARGS__; } \
using cx_value_tag = void; \
} val; \
return val; \
}()
template <typename T>
concept cx_value = requires { typename T::cx_value_tag; };
auto func(cx_value auto x) {
constexpr auto val = x();
std::cout << "Constexpr value: " << val.val() << '\n';
}
class S {
public:
constexpr S(const int val) : val_(val){}
int val() const {
return val_;
}
private:
int val_;
};
int main() {
constexpr S non_structural_value{420};
func(CX_VALUE(non_structural_value));
}
Issue is that clang rejects it, gcc accepts it.
Which compiler is right(or is it maybe underspecified in the standard)?
This has nothing to do with the properties of the class S
.
The problem can be reduced to
struct S {};
int main() {
constexpr S s{};
[]{
struct {
constexpr auto operator()() { return s; }
} val;
};
}
The problem is that s
is being odr-used here in return s;
because it doesn't have the lvalue-to-rvalue conversion applied to it (because it is of class type). And s
is not odr-usable in this scope.
For the same reason you would need to capture s
if you tried to write []{ return s; }
instead. But in the case above capturing won't help either, s
will still not be odr-usable in the scope of the local class.
Clang is correct.