'How to prevent std::min and max to return NAN if the first element of the array is NAN?

Is there a way to make min/max (std::min_element) ignore all NANs? I mean, it seems to ignore NANs in the middle but not if the first element is NAN.

Sample:

template <typename T> inline void GetMinMax(const T* data, const int len, T& min, T& max)
{
    min = *std::min_element(data, data + len);
    max = *std::max_element(data, data + len);
}

float min, max;
std::array<float, 4> ar1 = { -12, NAN, NAN, 13 };
GetMinMax<float>(&ar1[0], ar1.size(), min, max); //min: -12. max: 13

std::array<float, 4> ar2 = { -12, 3, 13, NAN };
GetMinMax<float>(&ar2[0], ar2.size(), min, max);//min: -12. max: 13

std::array<float, 4> ar3 = { NAN, -12, 3, 13 };
GetMinMax<float>(&ar3[0], ar3.size(), min, max);//min: -nan(ind). max: -nan(ind)  !!!!


Solution 1:[1]

NAN compares with other numbers is screwy, see What is the result of comparing a number with NaN?.

So what you need to do is to provide a custom compare function so that NAN isn't the element std::min_element returns. Probably just make "NAN < x" return false and "x < NAN" return true. Similar for ">" for std::max_element. Or try overloading <=>.

Note: the solution might depend on your implementation of the STL, depending on which comparison operator the implementation uses.

Solution 2:[2]

It does work but I'm wondering if there is a more compact form to write it

You could get rid of the intermediate variables to make it more compact:

f({
    std::make_shared<DerivedClassA>(), 
    std::make_shared<DerivedClassB>(),
});

Since all access specifiers are public, you can make the class definitions more compact by using struct:

struct DerivedClassB : AbstractClass {
    int get() const override { return 1; }
};

Solution 3:[3]

Besides what @eeronika is suggesting, you can also implicitly call std::shared_ptr constructor by passing raw pointers:

int main () {
    std::vector<std::shared_ptr<AbstractClass> > _classes;
    _classes.emplace_back(new DerivedClassA);
    _classes.emplace_back(new DerivedClassB);
    std::cout << f(_classes) << "\n";
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Goswin von Brederlow
Solution 2 eerorika
Solution 3 Expurple