0

I need a static method of my Base class to have a default parameter value of type Derived. Is there a way to implement this without use of overloading? (see here).

class Base;
class Derived;
Derived make_derived(void);

class Base
{
  public:
    static void problem_here(Base && = make_derived());
};

class Derived : public Base
{
};

Derived make_derived()
{
  return Derived();
}

... gives me an error about the usage of the incomplete type Derived. How ever, I cannot place the definition of Derived in front of problem_here because it must be defined after the definition of its base class Base.

Unfortunately, returning a pointer from make_derived is not an option.

Overloading problem_here is the only thing I came up with until now, but as the "real" problem_here method takes 2 (and another one 3) parameters, and it's part of a library, this gives me ...

static void problem_here(Thing const &, Base const &);
static void problem_here(Thing const &, Base &&);
static void problem_here(Thing const &); // Default param "hack"
static void problem_here(Thing &&, Base const &);
static void problem_here(Thing &&, Base &&);
static void problem_here(Thing &&); // Default param "hack"

.. for only the two parameter case.

Is there a way to avoid writing all those function signatures, while still maintaining the same performance (no unneccessary copy/move construction for any parameter constellation) and same behaviour on the caller site?


I should add that there are multiple functions like problem_here and all need access to the protected constructor of Derived (and to those of its many siblings). So the main reason to make these methods static members of Base is to be able to friend class Base; in each of the derived classes instead of friending every function.


Refactoring showed me, that I could move the code accessing the protected constructors of the derived classes into a single factory function. That way, I'm able to move the functions with the default parameters outside Base and let the call the factory. Now I still have to friend every one of those functions, but only a single time (in Base to give them access to the factory). I could circumvent this by placing all functions into a helper class and friending it instead, but that looks like a hack to me.

class Base
{
  friend class Helper; // The Hack
  friend void no_problem_here(Base &&); // No hack, more writting


  protected:
    static void factory(Thing && from_which_I_can_construct_the_correct_derived_class);
    // return type void to keep it simple, move parameter type because special cases
    // handled in "trampoline" functions and a copy of the Thing must be stored either
    // way.
};
class Derived : public Base
{
  friend class Base;
  // protected constructor omited for simplicity.
}


void no_problem_here(Base && = make_derived());
// ...
void no_problem_here(Base && b)
{
   // work, and then call Base::factory
}

// or

class Helper
{
  protected:
    // Constructors ...
  public:
    static void no_problem_either(Base && = make_derived());
};
4
  • 1
    What does problem_here do? Can't you just move it outside Base? Commented Mar 7, 2014 at 9:43
  • In the real case, it uses its first parameter to determine which (there are more than just Derived) derived class to instantiate, combines this with the second parameter and returns that. For that it needs access to the (all protected because of strong preconditions) constructors of the derived classes. As there are multiple functions like this, I would need to friend each of them in every derived class. Commented Mar 7, 2014 at 9:55
  • 1
    I suppose a template base is out of the question. Commented Mar 7, 2014 at 9:57
  • At first I thought yes, but letting the template base inherit from the realy base could partially work... (Like Derived -> Interim<Derived> -> Base) ... but would take the method out of the scope of Base. Commented Mar 7, 2014 at 10:07

1 Answer 1

4

You can make declarations multiple times, so the following workaround might help:

class Base;
class Derived;
Derived make_derived(void);

class Base
{
public:
    static void problem_here(Base &&);
};

class Derived : public Base {};

void Base::problem_here(Base && = make_derived()) { /* ... */ }

If there's a problem factoring the code like that, you can always insert a little trampoline function:

 class Base
 {
 public:
     static void problem_here(Base &&);
 private:
     static void problem_here_impl(Base &&);
 };

 inline void Base::problem_here(Base && x = make_derived())
 { problem_here_impl(std::move(x)); }
Sign up to request clarification or add additional context in comments.

3 Comments

Isn't it easier then to introduce the overloaded function declaration inline void Base::problem_here() { problem_here(make_derived()); } ?
@DanielOertwig: That would have different semantics, as it wouldn't allow problem_here(my_other_derived()).
Of course, if I use overloading: static void problem_here(Base &&); and static void problem_here(void);. But refactoring really showed me something: I was able to move all the code that needs access to the derived constructors into a single factory function, which doesn't take default parameters but can be called from the (now trampoline-like) functions with default parameters (which I have moved outside the base class, see edit of my question). So using trampline(s) and moving the default parameter functions outside Base actually solved this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.