From my understanding, dependent name lookup doesn’t take place until template instantiation, and template invocations in a discarded if-constexpr statement are not instantiated. As such, I would expect a template or generic lambda that is ill-formed, due to missing dependent names, to not produce compilation errors as long as they are only used in discarded if-constexpr statements. This appears to be the case in some instances. For example, take:
struct Struct {};
Struct s;
template<typename T>
void foo(T& s) {
s.non_existing_member = 0;
}
struct A {
template<typename T>
void operator()(T& s) { // note 'void' return type
s.non_existing_member = 0;
}
};
struct B {
template<typename T>
auto operator()(T& s) { // note 'auto' return type
s.non_existing_member = 0;
}
};
As expected, these do not produce compilation errors:
if constexpr (false) {
foo(s);
A{}(s);
}
[](auto& s) {
if constexpr (false) {
s.non_existing_member = 0;
}
}(s);
However, these do, complaining about the missing member:
if constexpr (false) {
auto bar = [](auto& s) {
s.non_existing_member = 0;
};
// error: no member named 'non_existing_member' in 'Struct'
// bar(s); // note: in instantiation of function template specialization 'main()::(anonymous class)::operator()<Struct>'
// B{}(s); // note: in instantiation of function template specialization 'B::operator()<Struct>' requested here
}
I don’t quite understand what is different about the above two cases. I get similar errors referencing dependent type names, e.g. typename T::Type
. Being explicit about the generic lambda’s template parameter (C++20) and void
return type doesn’t work either:
auto bar = []<class T>(T& s) -> void {
s.non_existing_member = 0;
};