Werner Erasmus
Werner Erasmus

Reputation: 4076

Unnamed default arguments to prevent ambiguities

I have a class that contains a collection of (persistent) cameras based on some configuration. Various classes are associated with the collection, and the collection provides various interfaces to the actual implementation. Each camera user is associated with the collection in its own way (one can almost consider it to be associated with its own collection, but the implementation might consolidate all responsibilities e.g:

#include <memory>
#include <map>

enum eCameraType{ eCameraType_IR, eCameraType_HDTV };
template <class CameraIF>
struct CameraCollectionIF
{
  virtual CameraIF& camera( eCameraType, typename CameraIF::Tag = typename CameraIF::Tag() ) = 0;

  protected:
    ~CameraCollectionIF(){}
};

struct CameraControlIF_A
{
  struct Tag{};
  virtual void doX() = 0;
};
struct CameraControllerA
{
  void foo()
  {
    //Gets the camera in terms of responsibility associated with
    // applicable control IF, but other classes can get camera (control) in
    // terms of their responsibility, and that without ambiguity...
    collection_->camera( eCameraType_HDTV ).doX();
  }

  std::shared_ptr<CameraCollectionIF<CameraControlIF_A>> collection_;
};

struct CameraControlIF_B
{
  struct Tag{};
  virtual void doY() = 0;
};
struct CameraControllerB
{
  void foo()
  {
    //Gets the camera in terms of responsibility associated with
    // applicable control IF, but other classes can get camera (control) in
    // terms of their responsibility, and that without ambiguity...
    collection_->camera( eCameraType_IR ).doY();
  }

  std::shared_ptr<CameraCollectionIF<CameraControlIF_B>> collection_;
};

//Now implementation of actual collection...

struct Camera : CameraControlIF_A, CameraControlIF_B
{
  //etc...
};

struct CameraCollectionForConfigurtionX :
  CameraCollectionIF<CameraControlIF_A>,
  CameraCollectionIF<CameraControlIF_B>
{
  private:
    //Assume for now all camera types shall exist in map, therefore lookup can't
    // fail...
    virtual CameraControlIF_A& camera( 
      eCameraType cameraID, CameraControlIF_A::Tag ) override
    {
      return( *cameras_[cameraID] );
    }
    virtual CameraControlIF_B& camera( 
      eCameraType cameraID, CameraControlIF_B::Tag ) override
    {
      return( *cameras_[cameraID] );
    }
    //etc...
    std::map<eCameraType, std::unique_ptr<Camera>> cameras_;
};

// Other configurations may exist that hold different collection of cameras....

The rationale of above mentioned can be argued, but it does provide decoupling between various controllers and their cameras independent of how the system is configured.

My question is:

As the virtual functions "camera" are never called via the public interface of the collection, I suppose one does not have to specify the default argument to be the same as that of the base, in fact, it is OK to omit it entirely:

virtual CameraIF& camera( 
  eCameraType, typename CameraIF::Tag = typename CameraIF::Tag() ) = 0;

vs:

virtual CameraControlIF_A& camera( 
  eCameraType cameraID, CameraControlIF_A::Tag );

Added to the question concerning default arguments, is the above mentioned technique to prevent ambiguous overloads (in implementation) common?

Upvotes: 1

Views: 70

Answers (1)

Dietmar K&#252;hl
Dietmar K&#252;hl

Reputation: 153820

When overriding a virtual function which is declared with a default argument in the base you can add another default argument and it can even have a different value! However, specifying default arguments in overriding function is an extremely bad idea, using different values doubly so. In any case, you don't need to specify the default but you do need to take a corresponding parameter as otherwise it isn't an overriding function: of a function to be an override it has to match the base class declaration exactly (except that the return type can be covariant if it a pointer or a reference). In C++ (since the 2011 revision) you can also follow your override declaration with the override [contextual] keyword to have the compiler verify that the declaration is, indeed, an override.

Upvotes: 1

Related Questions