1

Is it valid, to pass *this to a base class constructor?

template<class Lambda>
struct EmptyL : Lambda
{
    EmptyL() : Lambda(*this) //<- is this valid c++?
    { }
};

int main () {    
auto l = []() { return 34; };
auto a = EmptyL<decltype(l)>();
return a();
}

EDIT1:

  • Why do I do this? Because the ClosureType generated by a lambda expression is not default constructible. And by this "Trick" I am able to default construct such a ClosureType.
  • Additionaly the requirements for the template parameter Lambda are, that it has to be empty => static_assert(std::is_empty_v<Lambda>)
Kilian
  • 533
  • 4
  • 11
  • 14
    Why would you need to do that? Your base class already has its `this` – Justin Oct 11 '17 at 18:16
  • 1
    It is valid syntax but does not make sense, why would you copy construct from uninitialized? – Slava Oct 11 '17 at 18:17
  • 3
    Beware that `*this` will not have been initialized yet. It's hard to imagine a situation where this would be useful or do what you wanted. – François Andrieux Oct 11 '17 at 18:22
  • 7
    This is a horrible question. Sure, technically, yes, passing `*this` to a base class constructor is okay, but that doesn't even remotely make your example okay, and posting "yes" as an actual answer would be so misleading to be actively harmful. This is like asking "is it okay to add two unsigned integers" with an example of `unsigned f() { unsigned u1, u2; return u1 + u2; }`. –  Oct 11 '17 at 18:22
  • 1
    There is the potential for a good question in here, but your example is flawed. What are you really trying to do? – user4581301 Oct 11 '17 at 19:05
  • This makes perfect sense and I used to use this (before CRTP was something that passed code reviews without much pressure). – lorro Oct 11 '17 at 19:56
  • I don’t think the constructors are specified for lambda types, so even though you can inherit from lambdas (and this is useful), I don’t think you can legally pass `*this` to the lambda’s constructor. – Daniel H Oct 11 '17 at 20:02
  • 1
    I recently did something similar: https://stackoverflow.com/q/57007728/1896169 – Justin Aug 23 '19 at 17:48
  • Assuming the accepted answer in the linked question is correct, this is valid. This is effectively the same thing, just with a derived class thrown into the mix. You probably also need `std::is_trivially_copyable_v`, otherwise the copy constructor could do unexpected things. – Justin Aug 23 '19 at 22:15

1 Answers1

2

This is valid AND is perfectly useful: your base class might have a template ctor which will then know the descendant's type.

struct Lambda {
    template<typename Desc>
    Lambda(const Desc&)
        : myType(Desc::myType)  // static in Desc
        , arity(Desc::arity) {} // static in Desc
    Type myType;
    const size_t arity;
};

At this point, we have runtime type enum w/o virtual table, we can extract arbitrary number of type-dependant params to members and you don't need to change all ctor calls in all descendants if you add one more (which is especially painful for virtual base classes otherwise), or worse yet, have virtual fns cor these. You just pass this everywhere - it's even macro-friendly :).

Yes, you can circumvent it by passing something else than this. No, it's not a safety function - it's a convenience function. This is very similar to CRTP, but the base is not a template as it doesn't need compile-time descendant type in the entire class, only inside the (template) ctor.

lorro
  • 10,687
  • 23
  • 36
  • I'd say however that his example invoke undefined behavior, especially if the lambda has a state. – Guillaume Racicot Oct 11 '17 at 19:44
  • Can you please elaborate why? In Desc, I assume myType and arity to be static constexpr const if that's misleading... – lorro Oct 11 '17 at 19:57
  • @lorro : Many thanks for your anser! Do you have a quote from the Standard to verify that it is valid? – Kilian Oct 12 '17 at 13:17
  • @Kilian : I don't expect you'll find any specific part of the standard explicitly saying this. It's just that a template class can use pointers of type that's the template parameter anywhere - Lambda is defined at this point. – lorro Oct 12 '17 at 19:33