0

Let's consider definition:

struct ClassWithMember
{
    int myIntMember = 10;
}

I'd like to get myIntMember's default value, but do not create another instance of the class

// IMPOSSIBLE int myInt = ClassWithMember::myIntMember;  
// MUST AVOID int myInt = ClassWithMember().myIntMember;

I know workaround, but dislike it:

struct ClassWithMember
{
    static const int myIntMember_DEFAULT = 10;
    int myIntMember = myIntMember_DEFAULT;
}
int myInt = ClassWithMember::myIntMember_DEFAULT;

Because it needs extra line. And I cannot define inline static pointers like static const int *const INTEGER11_DEFAULT = 0x100088855;, such pointers must be defined in .cpp file, in .hpp is only declaration. Many of my classes are header-only, so create excess .cpp for this value isn't good idea.

Here is the similar question for C#

Community
  • 1
  • 1
kyb
  • 7,233
  • 5
  • 52
  • 105
  • 1
    "I know workaround, but dislike it" .... may be you should explain why ?? – HazemGomaa Oct 18 '16 at 17:48
  • Because it needs one more line. And I cannot define inline static pointers like `static const int *const INTEGER11 = 11;`, pointers must be defined in `.cpp` file, in `.hpp` only declaration. – kyb Oct 18 '16 at 18:00
  • "static const int *const INTEGER11 = 11" is not valid statement, and this is not the same as the question above that is all about accessibility... please edit your question to match your real concern. – HazemGomaa Oct 18 '16 at 18:07
  • real concern is **get default value of class member without creating new object**. Pointer or not does not meter. – kyb Oct 18 '16 at 18:16
  • "is not valid statement" - Yes. And that is problem, but is secondary. – kyb Oct 18 '16 at 18:17
  • 1
    I think this is an interesting question. In-class member initializers were made as a kind of shortcut to writing the same initialization list for constructors, so we all thought of the "default" values as existing in that fashion; unattainable (unless set through some other global). Looking at it them in this light, though, one is quite justified in asking "Why? The value is right there!" – AndyG Oct 18 '16 at 19:31

2 Answers2

2

I suppose that, for you, is only another workaround but I think is a little (only a little) more practical.

If you save the default value as a static const that is returned by a static method, you can avoid the additional line in the cpp file.

The following example do the trick in a template wrapper (with default value as template parameter with a default vaule; just for fun) but the template part is just to avoid the duplication of code in the example

#include <iostream>

template <typename T, T defTpl = T{}>
struct wrapperWithDef
 {
   static T getDefVal ()
    { static T const def { defTpl }; return def; }

   T myTMember { getDefVal() };
 };

int main()
 {
   wrapperWithDef<int>          wi;
   wrapperWithDef<long, 3L>     wl;
   wrapperWithDef<int *>        wp;

   // print "0, 3, (nil)" (clang++) or "0, 3, 0" (g++)
   std::cout << wi.myTMember << ", " << wl.myTMember << ", "
      << wp.myTMember << std::endl;

   // print "5, (nil), 1" (clang++) or "5, 0, 1" (g++)
   std::cout << wrapperWithDef<unsigned, 5U>::getDefVal() << ", "
      << wrapperWithDef<long *>::getDefVal() << ", "
      << wrapperWithDef<bool, true>::getDefVal() << std::endl;

   return 0;
 }
max66
  • 65,235
  • 10
  • 71
  • 111
1

I call this solution workaround

struct ClassWithMember
{
    static const int myIntMember_DEFAULT = 10;
    int myIntMember = myIntMember_DEFAULT;
}
int myInt = ClassWithMember::myIntMember_DEFAULT;

For pointers it will look more complicated

//.hpp
struct ClassWithMember
{
    static AnotherClass* const myMember_DEFAULT;  //=X; Assignment not allowed
    AnotherClass* myMember = myMember_DEFAULT;
}
//.cpp
AnotherClass* const MyNamespace::ClassWithMember::myMember_DEFAULT = pAnotherInstance;
//usage
auto *my = ClassWithMember::myMember_DEFAULT;
kyb
  • 7,233
  • 5
  • 52
  • 105