-2

I'm trying to implement a constexpr find with c++17 to find the index of a matching element in an array (from cppreference) very similar to this question. Below is a very simple implementation with an int array.

namespace mine{
    template<typename InputIter, typename T>
    constexpr inline InputIter find(InputIter first, InputIter last, const T& val)
    {
        for(; first!=last; ++first)
            if(*first == val) return first;

        return first;        
    }
}

int main()
{
    const std::array<int, 5> a{4, 10, 5, 889, 45};
    auto b = mine::find(a.begin(), a.end(), 5);
    auto c = std::distance(a.begin(), b);

    return c;
}

The problem is GCC trunk is unable to deduce mine::find at compile time!! (live code mine::find). However, simply by changing the switch to -std=c++2a (as c++20 marks std::find as constexpr), std::find gives me the expected results (live code std::find).

Edit: How can I get the same results as std::find with mine::find for the same optimization level without changing code in main()? (mind::find can of course be changed keeping a similar interface) And what makes GCC optimize std::find better for the same optimization level?

Edit 2: Declaring b here as constexpr gives an error (live code with error)

int main()
{
    const std::array<int, 5> a{4, 10, 5, 889, 45};
    constexpr auto b = mine::find(a.begin(), a.end(), 5);
    auto c = std::distance(a.begin(), b);

    return c;
}

Note: Clang trunk seems to deduce mine::find correctly. But this has little to do with constexpr IMHO as clang deduces the result even without it.

Xenonamous
  • 29
  • 7
  • If you care about this, why aren't you using `-O3`? – Brian Bi Aug 10 '19 at 19:41
  • 2
    What do you mean "unable to deduce"? Your link shows it compiling, and your example doesn't require it to be `constexpr`? – Barry Aug 10 '19 at 19:41
  • 1
    If you want to call your method at compile time, use it in constant expression: add constexpr for `b`. Currently, you just check how good is compiler to optimize the code. – Jarod42 Aug 10 '19 at 19:44
  • 1
    @Barry I think they are asking about this [error](https://godbolt.org/z/PR5aJk). – Bob__ Aug 10 '19 at 20:04
  • @Bob__ I don't think so. OP provided two code examples, one with `std::find` (optimized away), and second with `mine::find` (non-optimized). They just use the wrong wording. – Yksisarvinen Aug 10 '19 at 20:16
  • 2
    @Xenonamous If your question is "why compiler doesn't generate any assembly for `std::find`", then the answer is "because it knows how to optimize standard functions better than non-standard". GCC happens to optimize your `mine::find` as well, when you pass `-O3` flag instead of `-O2`: https://godbolt.org/z/UvGHut – Yksisarvinen Aug 10 '19 at 20:22
  • @Bob__ I don't make assumptions about what people mean. It's up to them to clearly state what the problem is, it's not up to us to guess. – Barry Aug 10 '19 at 22:23
  • @Yksisarvinen you are right. My intention was to understand what is making `std::find` be better optimized compared to the hand made function. I understand that `-O3` forces the compiler to work harder to optimize the code but what is making GCC optimize away `std::find` compared to `mind::find` for the same optimization level? – Xenonamous Aug 10 '19 at 22:51
  • @Barry and @Jarod42, declaring `b` as `constexpr` just gives out an error as @Bob__'s comment shows – Xenonamous Aug 10 '19 at 23:04
  • To answer such question would require a person deeply involved in compiler creation, or at least knowledgeable of different options for optimizing (note that `-O3` is pretty much an alias for a lot of separate optimization options). It's pretty much how creators of gcc wanted it to work, so it works this way. My guess is that knowing all the ins and outs of standard library enables compiler to optimize it much better and faster than doing the same for unknown functions from the outside. The increased cost of optimizing user functions lead to decision to put it in the higher optimization level. – Yksisarvinen Aug 10 '19 at 23:11
  • @Xenonamous So please edit your question with the actual code that your question is about. Neither nor question, nor the links, declare `b` constexpr. – Barry Aug 11 '19 at 00:55
  • @Xenonamous: with missing `static`, [constexpr version works](https://godbolt.org/z/inWVEw). – Jarod42 Aug 11 '19 at 08:48
  • @Jarod42 Thank you very much `static` was the missing link in my understanding. The nice part is that making this `static` means that the compiler is really able to do compile time evaluation even with `-O0` (boils down to a `MOV` instruction as expected). Can you please submit this as an answer? – Xenonamous Aug 11 '19 at 10:51

1 Answers1

0

constexpr function are not required to be called at compile time unless there are used in const expression. You rely then to compiler optimization.

Turning your (calling) code in constexpr ensures compile time computation:

int main()
{
    static constexpr std::array<int, 5> a{4, 10, 5, 889, 45};
    constexpr auto b = mine::find(a.begin(), a.end(), 5);
    constexpr auto c = std::distance(a.begin(), b);

    return c; // return 2 directly
}

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302