1

so I am trying to construct a class with helper method, namely:

class Type{
    int a, b, c;

    friend auto helper(auto);
    friend auto test_helper(auto);
    /* couples test with implement */

public:
    void method(){
        helper(this);
    }
};

But making helper a friend function couples the test with implementation if we want to test helper.

So I want to make helper a free function, namely:

auto helper(int&,int&,int&);
auto test_helper(int&,int&,int&);

class Type{
    int a, b, c;
public:
    void method(){
        helper(a,b,c);
    }
};

This, however, makes the code a lot more tedious when data members are many. So, I came up with an idea to construct an helper struct that has exact data member as Type but with all data member being public, so that we'll be able to simply pass in the handle of such HelperType, maybe something like:

struct HelperType{
    int a, b, c;
};
auto helper(HelperType* a);
auto test_helper(HelperType* a);
void Type::method(){
    helper(static_cast<HelperType*>(this));
}

Is there any elegant approaches to construct such HelperType struct? Such as a generic wrapper or perhaps with inheritance?

Taylor Huang
  • 245
  • 2
  • 8
  • Best I can think of is doing something with `std::tuple` and a pack of variadic template parameter list. – πάντα ῥεῖ Jul 08 '18 at 10:54
  • 2
    Why don't you just make a getter functions for those values? – user7860670 Jul 08 '18 at 10:54
  • @VTT It is because those data member should not be publicly visible and also we want to have side effect on the data-member. – Taylor Huang Jul 08 '18 at 11:04
  • @πάνταῥεῖ what do you mean? – Taylor Huang Jul 08 '18 at 11:05
  • 1
    You painted your problem in what I consider overly broad strokes, but I feel you have yourself an [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). Maybe the helper is too complex? Maybe it's too complex because your design lacks the S in SOLID? – StoryTeller - Unslander Monica Jul 08 '18 at 11:06
  • @StoryTeller I believe that is my exact problem. And it doesn't have to be a lot of parameters passed in to make them look tedious. I also don't want my question overly specified that give rise to some work around. – Taylor Huang Jul 08 '18 at 11:22
  • @TaylorHuang I mean that you could try an approach to bind the parameter variable types to the helper function using template meta programming and a variadic type parameter pack. – πάντα ῥεῖ Jul 08 '18 at 11:25
  • @TaylorHuang Here's a [similar thing](https://stackoverflow.com/questions/18251815/creating-an-array-initializer-from-a-tuple-or-variadic-template-parameters). – πάντα ῥεῖ Jul 08 '18 at 11:29
  • You can make those getters not publicly visible and mark functions that should access those getters as friends. I don't see any problem with having side effects on data members either. – user7860670 Jul 08 '18 at 11:35
  • 1
    "making helper a friend function couples the test with implementation" -> do you need this for unit tests? If yes, maybe `#define private public` in that test only would be an acceptable solution? It's not very elegant, but doesn't need any modifications of tested code. – joe_chip Jul 08 '18 at 11:45
  • @joe_chip indeed I need that for unit test this works of course but I would like to avoid this – Taylor Huang Jul 08 '18 at 12:57

1 Answers1

0

I have no simple solution to create HelperType from Type (only things coming to mind involve heavy metaprogramming or macro usage). However building Type from HelperType would be quite trivial, using private inheritance. From Derived class (cppreference.com):

When a class uses private member access specifier to derive from a base, all public and protected members of the base class are accessible as private members of the derived class.

// Could be renamed "TypePrivateMembers" or "TypeData"
struct HelperType{
    int a, b, c;
};

auto helper(HelperType* a);

class Type : private HelperType {
public:
    // a,b,c can be accessed in Type class scope.

    void method(){
        helper(this);
    }
};

Live demo

However, still from cppreference (emphasis mine):

Private inheritance can also be used to implement the composition relationship (the base class subobject is an implementation detail of the derived class object). Using a member offers better encapsulation and is generally preferred unless the derived class requires access to protected members (including constructors) of the base, needs to override a virtual member of the base, needs the base to be constructed before and destructed after some other base subobject, needs to share a virtual base or needs to control the construction of a virtual base. [...]

This is the recurring composition over inheritance debate. This question has already been asked many times on StackOverflow, here are a few interesting link on the topic (in general & for this specific case):