Skip to content

emp::Min and emp::Max initializer_list overloads cannot be instantiated #550

Description

@karpovantonme

What happens

emp::Min and emp::Max, the variadic-list overloads in include/emp/math/math.hpp, cannot be instantiated. Any call to them fails to compile.

template <typename T>
const T & Min(std::initializer_list<const T &> lst) {
  emp_assert(lst.size > 0);
  auto min_found = lst.begin();
  ...
}

std::initializer_list<const T&> is ill-formed: the implementation holds a const _Ep*, and a pointer to a reference does not exist. Reduced to a standalone file so nothing else is in play:

$ clang++ -std=c++17 -fsyntax-only test.cpp
initializer_list:63:12: error: '__begin_' declared as a pointer to a reference of type 'const int &'
   63 |   const _Ep* __begin_;
      |            ^
test.cpp:15:19: note: in instantiation of template class 'std::initializer_list<const int &>' requested here
   15 |   return Min<int>({a, b, c});

GCC gives the equivalent error.

Second thing in the same two functions: emp_assert(lst.size > 0) is missing the call parentheses, so it does not check the size, it takes the address of the member function.

Why it went unnoticed

Nothing in the library or the test suite calls them: grep -rn "Min({\|Max({" . finds no call sites, and there is no test touching initializer_list for these. Since they are templates, the body is never instantiated, so the code compiles fine as long as nobody uses the feature.

Suggested direction

Taking std::initializer_list<T> instead compiles. The return type needs a decision though: returning const T& into the list is only safe while the backing array is alive, which for a braced list ends at the end of the full expression, so const int& m = emp::Min({a, b, c}); would dangle. Returning T by value avoids that. Since the current signature cannot compile, nothing depends on it, so either choice is free.

I have not sent a patch: doc/dev/ai-usage-guidelines.md says agentic AI should not be used to generate core-library source, and this is core library source. Flagging it so a human can decide the signature and write it.

Found with a cppcheck --enable=warning sweep over the repository (it reports returnReference at math.hpp:312 and :323), then narrowed down with the compile test above.

Activity

  1. karpovantonme commented on Aug 3, 2026

    @karpovantonme
    Author

    A follow-up on the "no patch" note above, since I would rather ask than assume.

    I have the fix working locally: take std::initializer_list<T>, return T by value, and add the missing parentheses on lst.size(). The loop body is unchanged. It compiles and passes a quick check:

    #include "emp/math/math.hpp"
    #include <cassert>
    int main() {
      assert(emp::Min({3, 1, 2}) == 1);
      assert(emp::Max({3, 1, 2}) == 3);
      assert(emp::Min({2.5, 0.5, 1.5}) == 0.5);
    }
    $ clang++ -std=c++20 -I include emp_check.cpp -o emp_check && ./emp_check
    

    By value rather than const T& because a braced list's backing array dies at the end of the full expression, so const int& m = emp::Min({a, b, c}); would dangle. Since the current signature cannot be instantiated at all, nothing depends on the old return type.

    Whether that should come from me is your call, not mine. doc/dev/ai-usage-guidelines.md says agentic AI should not generate core-library source, and this is core-library source, which is why I stopped at the report. If you would like the patch anyway I will open it, marked as AI-assisted per point 7 and with the human manager named per point 2. If you would rather write it yourselves, everything you need is above and I will stay out of it.

    Two things worth deciding either way: whether Min/Max should return by value, and whether these overloads deserve a test, since the absence of one is why an uninstantiable template sat here unnoticed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions