Keeping lambda confused members

I was reading Scott Meier's Effective Modern C ++ and got into a subject where he suggested using and lambda

instead of . I understand his argument and his claims of shortcomings and I agree with him.std::function

std::bind

std::function

As of today, I decided to switch to storage templates lambda

(which don't need mutators). I understand that the type of each lambda

is only known to the compiler, and even two identical ones lambda

will have different types, since the following code compiles and works just fine?

template<typename LambdaT>
class CaptureLambda
{
public:
    CaptureLambda(const LambdaT& fn)
        : mActionFn(fn) // initialize mActionFn to a user supplied lambda
    {}

private:
    LambdaT    mActionFn{ []{} }; // initialize mActionFn to an empty lambda
};

      

My confusion is, how is it that mActionFn

the default is initiated by an empty lambda with a different type inside member declarations, but the class constructor happily accepts a different type in its arguments lambda

? are they cast

capable of each other? if so why is the following compiler printing?

// Class stuff...

template<typename T>
void resetActionFn(const T& newFn) { // setter member
    mActionFn = newFn;
}

// Class stuff...

      

+3


source to share


1 answer


Initializers for non-static data input members will only be used if the constructor does not specify another initializer.

Considering

struct S {
  int i = 3;
  S() : i(4) { }
};

      

you don't get a default constructor that initializes i

before 3

and then reinitializes before 4

, you just get a constructor that initializes i

before 4

.



It's the same with your class. You don't have a constructor that doesn't initialize mActionFn

, so the initializer will never be used.

Now, as Peter S. points out in the comments, in general, the intialiser should still be semantically correct, but your data member is of a dependent type, so the expiration cannot be checked during template definition, and the initializer will never be instantiated, since it is not used, so no error was found during instantiation either. A similar simpler example is

template <typename T>
struct S {
  T x = 3;
  S() : x(0) { }
};
int main() {
  S<void*>();
}

      

which is tacitly accepted by GCC, even though it 3

is an invalid initializer for a type field void*

. Klang rejects him. It is not clear in the standard whether the instantiation of the template creates any unused NSDMIs, and some compilers create them only as needed. There is an agreement that they should only be created as needed, but there are some problems with this approach, so not all compilers implement this.

+4


source







All Articles