3

Does the standard library permit users to specialize function objects like std::plus and std::minus for custom types?

If the answer to my first question is yes, are users allowed to change the declaration of the call operator? For example, since C++14 std::minus::operator() is declared as follows:

constexpr T operator()( const T& lhs, const T& rhs ) const;

Would it be legal to change this operator such that it is no longer constexpr or returns double instead of T?

namespace std
{
    template <> 
    struct minus<MyArrayType>
    {
        double operator ()(const MyArrayType& x, const MyArrayType& y) const
        {
            return l2_norm(x - y);
        }
    };
}   // std
mentalmushroom
  • 2,261
  • 1
  • 26
  • 34
  • 2
    Shouldn't you override `operator -` instead? – user253751 Feb 22 '21 at 09:10
  • @user253751 Suppose, the operator - for this type is already defined, but I'd like to alter it's behavior such that it could be used differently. – mentalmushroom Feb 22 '21 at 09:11
  • 1
    Then you should use a different functor instead of std::minus. Make a mentalmushroom::l2_norm_minus instead – user253751 Feb 22 '21 at 09:15
  • @user253751 Well, makes sense, but imagine for my particular needs it would be more convenient to specialize std::minus. Moreover, I have a general curiousity :) – mentalmushroom Feb 22 '21 at 09:21
  • More interesting question is: WHY? Which algorithm uses this templates? Is this algorithm/template yours? – Marek R Feb 22 '21 at 09:50

1 Answers1

6

The rules for extending namespace std says:

It is allowed to add template specializations for any standard library class template to the namespace std only if the declaration depends on at least one program-defined type and the specialization satisfies all requirements for the original template, except where such specializations are prohibited.

(emphasis mine)

So in your case, adding a specialization for the program-defined type MyArrayType would work.

However, the return type of the member operator() must be MyArrayType, not double. Also, the member operator() must be constexpr.

Violating either of these means the specialization doesn't satisfy the requirements of the primary template.

cigien
  • 57,834
  • 11
  • 73
  • 112
  • Thanks, how do you understand the phrase "requirements for the original template"? Where are they described? – mentalmushroom Feb 22 '21 at 09:34
  • I'm not sure where the term "requirements for the original template" are written exactly. However, you can see that the requirements on the original(primary) template are that the return type and the parameter types must match. Also, the primary template must be callable in a `constexpr` context (from C++14). Another example would be that the member `operator()` must be const-qualified. – cigien Feb 22 '21 at 09:40
  • "Meaning" might also be part of "requirements" [arithmetic.operations#plus](https://eel.is/c++draft/arithmetic.operations#plus). But some other templates have clearly requirements/pre-conditions which seems not be the case here... – Jarod42 Feb 22 '21 at 09:58
  • Interesting question : https://stackoverflow.com/questions/52760580/will-specialization-of-function-templates-in-std-for-program-defined-types-no-lo – Bktero Feb 22 '21 at 10:26