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>{});
}

Reply via email to