17

I have some macros that need access to the type of the current class and I currently get away with this via a DRY-violating pattern:

struct ThisScruct{
    int a;
    double b;
    //example static method using this - purely example - not full usecase

    static size_t sum_offsets(){
       typedef ThisStruct SelfT;
       return offsetof(SelfT, a) + offsetof(SelfT, b);
    }
};

This comes up a lot with use of the offsetof keyword, at least in my own work.

Now before you lock onto this not being accessible via a static method - realize I just want to know how to get the type ThisStruct in a generic/macro friendly way from a static method context. I don't actually need/want an instance and am looking for way that actually works like the above without typedeffing SelfT.

Edit: Something similar is asked in Can I implement an autonomous self member type in C++? - but I am worried about a diamond problem forming with classes both inheriting from the accepted answer's Self class.

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
Jason Newton
  • 1,201
  • 9
  • 13
  • 2
    What does `declare_static_methods_using_offsetof` mean? The `typedef` you have is probably the best way of doing this. – Praetorian May 14 '15 at 03:57
  • @TonyD when these macros are invoked - I do not have access to "this" because the context is static methods. – Jason Newton May 14 '15 at 05:12
  • @Praetorian I've been using typedef for a long time to do this; I refuse to believe it is the best way to do it :-)! I filled in something concrete for declare_static_methods_using_offsetof – Jason Newton May 14 '15 at 05:16
  • I knew I'd seen this question before, finally managed to find it - https://stackoverflow.com/q/21143835/241631 Would you consider that a duplicate? – Praetorian May 14 '15 at 05:25
  • @Praetorian at face value I would; however the answer there will break with inheritance involved (two classes inheriting Self now being involved in a parent child relationship) if I'm reading it right. I'll edit my example again. Btw great memory - I searched for a prior question more than a few times. – Jason Newton May 14 '15 at 05:29
  • Sum of offsets doesn't make sense since it is cumulative. If you had a third variable, what would you get? If this is a base class and if you just took the address of the last variable and added the sizeof it, that would give you the offset of whatever follows. – cup May 14 '15 at 05:54
  • @JasonNewton Just noticed your "example static method" - do you realise that if you put the `typedef` just once in the `struct` definition, it can be used by any number of static member functions...? [see here](http://ideone.com/vjdK4B) And re your comment to me above - yeah - ADD_THIS was a stupid idea. – Tony Delroy May 14 '15 at 05:57
  • @cup - don't nit pick the example usecase – Jason Newton May 14 '15 at 06:12
  • There's no straightforward way to do this, but if you're really using it for structs, have you considered having a constexpr default constructor for the type and just making the method non-static? Calling ThisStruct{}.sum_offsets() isn't much worse than ThisStruct::sum_offsets(), and should optimize to the same thing with any reasonable compiler. – addaon Nov 18 '15 at 02:23

1 Answers1

4

You could use the CRT-pattern to access the typename generically, you just need to specify it in the inheritance list.

    template<class T>
struct Type { using type = T; };

struct ThisScruct : Type<ThisStruct> {
    int a;
    double b;

    // this function can be copy-pasted into every
    // struct definition, which is inherited from
    // Type and contains the members a and b
    static size_t sum_offsets(){
       typedef Type::type SelfT;
       return offsetof(SelfT, a) + offsetof(SelfT, b);
    }
};

You might rename Type to a more descriptive name. But you might consider replacing this functionality completely by the CRT-pattern, by moving the functions into the inherited struct.

    template<class T>
struct SumOffsets {
    static size_t sum_offsets(){
       typedef T SelfT;
       return offsetof(SelfT, a) + offsetof(SelfT, b);
    }
};

struct ThisStruct : SumOffsets<ThisStruct> {
    int a;
    double b;
};

The function sum_offsets can be accessed by ThisStruct::sum_offsets, because even static functions are inherited. There is no additional overhead, because neither virtual functions are involved nor SumOffsets has data members.

cmdLP
  • 1,658
  • 9
  • 19