0
// globally accessible variable. can be changed at runtime.
bool feature_flag = true

Class A
{
  UtilityClass obj_util;

  A(int x,int y,int z)
  {
  }
}

Class UtilityClass
{
  UtilityClass()
  {
  }
}

Main()
{
  A a(10,20,30);
}

When object to A is created, it instantiates UtilityClass object inside A and so calls UtilityClass() constructor.

My new scenario and problem:

when feature_flag is activated (true), some components will not be available in UtilityClass (don't ask me how), so UtilityClass() constructor call will fail.

To avoid this failure,

1) I want obj_util member to be removed when feature_flag = true

like

Class A
{
  if(feature_flag == false)
    UtilityClass obj_util;

  A(int x,int y,int z)
  {
  }
}

(or)

2) I don't want UtilityClass() constructor to be invoked when creating object to A. I also don't want to convert UtilityClass in Class A to UtilityClass* to avoid calling constructor, as there is a huge code associated with this object in Class A and needs change in lot of components inside. But I am pretty sure that none of that code path will be hit when feature_flag = true.

I want both scenarios coexisting just with the deciding condition of one flag (feature_flag). Is it even possible in c++?

I heard something about std::conditional but did not understand whether I can apply it in the following scenario.

For example, the following did not work

// globally accessible variable. can be changed at runtime.
bool feature_flag = true

Class A
{
  std::conditional <feature_flag, UtilityClass, DummyClass> obj_util;

  A(int x,int y,int z)
  {
  }
}

Also, I tried to fit std::conditional in .h file because all class definitions are present in .h files in my project, and it also doesn't seem to work.

Please note that I cannot create any dummy constructor in UtilityClass or for that matter cannot change code for UtilityClass.

Any hints or suggestions are appreciated. Thanks

Sudheer
  • 81
  • 7
  • Perhaps you need to have some run-time checks in the `UtilityClass` default constructor instead, so it will always work? – Some programmer dude Jan 16 '20 at 07:58
  • As I mentioned in my post, I cannot touch UtilityClass . Thanks – Sudheer Jan 16 '20 at 08:06
  • 1
    If the two only possible options you have (using pointers and modifying the class) can't be done (for "reasons") then you're out of options. And in my not humble at all opinion, if the `UtilityClass` depends on the `feature_flag`, it should have been designed and implemented to make sure that it doesn't fail at run-time because of the flag, no matter its value. – Some programmer dude Jan 16 '20 at 08:10
  • 3
    It sounds like you have a design problem. Perhaps you need to split `A` into a base (without the optional extra features) and a subclass (that adds them). – Toby Speight Jan 16 '20 at 08:12
  • @TobySpeight thanks. That is one solution I have in my mind. – Sudheer Jan 16 '20 at 08:44
  • @Someprogrammerdude agree that this is a design problem that someone did 8 years ago, and now we don't have enough resources to refactor this :-( – Sudheer Jan 16 '20 at 08:45

3 Answers3

2

You could use something similar to policy-based design here.

I would implement a class that stores the UtilityClass based on template-specialization of a boolean flag:

template<bool FeatureActivated> struct Feature;
template<> struct Feature<true> {
    UtilityClass utility;
};
template<> struct Feature<false> {};

Class A can activate this feature based on a boolean that is given as a template parameter:

template<bool FeatureActivated>
struct A : public Feature<FeatureActivated> {};

You can use A like this:

auto foo() {

    A<true> t;
    auto& feature = t.utility; //compiles

    A<false> t2;
    auto& feature2 = t2.utility; // does not compile

}

Here is the complete example: https://godbolt.org/z/b3Kmo7

Edit: This does not allow the feature to be turned on or off during run-time.

Stefan Groth
  • 154
  • 7
  • I like that approach, because it avoids pointers as the OP suggested. But to be fair I think its a complicated approach to solve an easy task just because the OP does not want to replace `obj_util.` with `obj_util->` which is a simple replace operation. So the size of the code base does not matter. He also claims that he is sure that `obj_util` will not be called when flag is false, so he could even omit the nullptr checks (which i would not advise). With a solution like this the code does not become more readable because it introduced unneeded complexity. Nonetheless +1 for the idea. – Taron Jan 16 '20 at 08:42
0

If you don't want to change obj_util to pointer, perhaps it might be reasonable to change it to a function:

class A {
public:
    A() { std::cout << "Constructor"; }
    void print() { std::cout << "Print"; }
};

bool feature_flag = true;

class B {
public:
    B() : obj_util(feature_flag) {
        if (feature_flag) {
            obj_ptr = std::make_unique<A>();

            // Syntax has to be changed to a function call
            obj_util().print();
        }
    }

private:
    std::unique_ptr<A> obj_ptr;
    A& obj_util() const { return *obj_ptr; }

};

Another option is to make a wrapper class, which replicates the interface:

class AWrapper {
public:
    AWrapper(bool enabled) {
        if (enabled) ptr = std::make_unique<A>();
    }
    void print() { ptr->print(); }

private:
    std::unique_ptr<A> ptr;
};

bool feature_flag = true;

class B {
public:
    B() : obj_util(feature_flag) {
        if (feature_flag) {
            // No need to change the syntax
            obj_util.print();
        }
    }

private:
    AWrapper obj_util;
};
VLL
  • 9,634
  • 1
  • 29
  • 54
-1

What abut storing a pointer to UtitlityClass instead of class itself. Prefer a unique_ptr. Then if your flag is true create the class otherwise you have nullptr. When using the class you have to do nullptr checks.

Class A
{
public:
  A(int x,int y,int z)
  {
      if( feature_flag == true ){
          // obj_util.reset( new UtilityClass() ); //c++11
          // since c++14
          obj_util = std::make_unique< UtilityClass >();
      }

      // can be anywhere int class
      if( obj_util != nullptr ){
          obj_util->doStuff();
      } 
  }
private:
  std::unique_ptr<UtilityClass> obj_util = nullptr;


}
Taron
  • 1,205
  • 2
  • 13
  • 29