https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86282
Jonathan Wakely <redi at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|UNCONFIRMED |RESOLVED Resolution|--- |INVALID --- Comment #1 from Jonathan Wakely <redi at gcc dot gnu.org> --- I think GCC's behaviour is correct, as required by the standard. Firstly, if constexpr in main() doesn't work the way you want, because there's nothing dependent (there is no possible version of the function where the condition will be true, so the program is ill-formed). Secondly, if constexpr doesn't short-circuit the instantation of templates and concepts used in the condition, so the entire thing is instantiated even if the actual boolean evaluation short-circuits. That can be solved by using two nested ifs: if constexpr (has_begin<decltype(p)>) if constexpr (has_begin<...>) Or using std::conjunction, which does avoid instantiating anything that isn't needed (but would require changing your code to use with that concept): https://en.cppreference.com/w/cpp/types/conjunction Here's a working version: #include <utility> #include <type_traits> #include <vector> template <typename type> concept bool has_begin = requires (type v) { { std::begin(v) } }; template<typename T> int f(T p) { if constexpr (has_begin<T>) if constexpr (has_begin<std::remove_reference_t<decltype(*std::begin(p))>>) return 0; return 1; } int main() { f(1); f(std::vector<std::vector<int>>{}); f(std::vector<int>{}); }