Search code examples
c++optional-parametersrule-of-three

Avoid Name Reservation for Unused Abstract Optional Function Arguments


I have a solver class template, whose solve-routine may be called with an optional ostream.

Under a specialization of said class template, the ostream is never used.

Question

Why can't I literally remove the character-sequence "fdsa" from the minimum example below, and have it achieve the same behaviour as what I expected analogously from the code foo?, namely that:

  1. I define foo in one single place.
  2. I need no label for the second argument of foo.
  3. I can call foo with either one or two arguments.

Minimum Example

#include <iostream>
#include <cassert>

template<typename T>
class OptionalWrapper{
    T* p;
public:
    const bool is_empty;
    OptionalWrapper(void):is_empty(true),p(NULL){}
    OptionalWrapper(T& r):is_empty(false),p(&r){}
    T& operator()(void){ assert(!is_empty); return *p; }
    T const& operator()(void)const{ assert(!is_empty); return *p; }
};

template<typename Tfloat>
struct Solver{
    // ... lot of other code
    void compute(Tfloat&x, OptionalWrapper<std::ostream> o=OptionalWrapper<std::ostream>() ){
        if(!o.is_empty) o()<<"solver<float>::compute("<<x<<");\n";
    }
};

template<>
struct Solver<double>{
    // ... lot of uncorrelated specialized code
    void compute(double&x, OptionalWrapper<std::ostream> fdsa=OptionalWrapper<std::ostream>() ){
        std::cout << "solver<double>::compute("<<x<<");\n";
    }
};

int main() {
    //
    float xf = 1;
    double xd = 2;
    //
    Solver<float> sf;
    Solver<double> sd;
    //
    sf.compute(xf,std::cout);
    sf.compute(xf);
    //
    sd.compute(xd,std::cout);
    sd.compute(xd);
}

Has it to do something with the rule of 3/5, that I cannot just replace OptionalWrapper<std::ostream> fdsa=OptionalWrapper<std::ostream>() with OptionalWrapper<std::ostream> =OptionalWrapper<std::ostream>() ?

(Remark: Defining the function outside of the class specialization body will result in acceptance by GCC and the above code as is without "fdsa" will be accepted by CLANG, MVSC, ICX, and ZIG. So maybe there is indeed not much insight to gain from the question. My apologies for only finding out now.)

What I expected

That I can use the same principle of overloading as with

int foo(int x, int=0){
    return 2*x;
}
int main() {
    foo(1);
    foo(2,3);
    return 0;
}

and not need to provide a label for y, the second argument. Basically I would assume that to the compiler the type of the second argument should not even matter because it will not be dealt with by the function body anyways.


Solution

  • OptionalWrapper<std::ostream>=OptionalWrapper<std::ostream>() has parsing issue, you need extra space:

    OptionalWrapper<std::ostream> =OptionalWrapper<std::ostream>().

    Demo.

    else >= is considered as greater_than, (similarly to old >> issue to close a double template).