1

I'm trying to understand why this snippet fails:

#include <iostream>

using namespace std;


template <typename Lambda>
struct Handler
{
  bool _isCompleted;

  bool isCompleted() { return _isCompleted; }

  Lambda _l;
  Handler(Lambda&& l) : _l(l) {}

  void call() { _l(this); }
};

int main()
{
  auto l1 = new Handler( [&](decltype(l1) obj )->
{
  obj->_isCompleted = true;
  cout << " is completed?" << obj->isCompleted() << endl;
});
  l1->call();
};

g++ 4.5 fails with:

test.cpp: In function ‘int main()’:
test.cpp:21:17: error: expected type-specifier before ‘Handler’
test.cpp:21:17: error: expected ‘,’ or ‘;’ before ‘Handler’
test.cpp:25:2: error: expected primary-expression before ‘)’ token
test.cpp:25:2: error: expected ‘;’ before ‘)’ token
test.cpp:26:7: error: request for member ‘call’ in ‘* l1’, which is of non-class type ‘int’

my understanding is that auto l1 should resolve to Handler<lambdaType>* and lambdaType should have a public function signature void( Handler<LambdaType>*). I don't see any blatantly wrong with the above example (you know, besides the ugliness and the slightly pathological cyclic dependency between the lambda and the handler type)

1
  • 3
    Aren't you essentially asking your compiler to synthetise a type out of thin air without any concrete information about it except that pathological cyclical self-dependency? Commented May 21, 2012 at 17:34

2 Answers 2

5

One problem is, as @Cat said, that template argument deduction just does not work for constructor calls. You always need to specify the template argument.

The other problem is nicely illustrated by Clang with the following snippet:

struct X{
  X(...){}
};

int main(){
  auto l = X([](decltype(l)& o){});
}

Output:

t.cpp:6:26: error: variable 'l' declared with 'auto' type cannot appear in its
      own initializer
  auto l = X([](decltype(l)& o){});
                         ^
1 error generated.

Obligatory standard quote:

§7.1.6.4 [dcl.spec.auto] p3

Otherwise, the type of the variable is deduced from its initializer. The name of the variable being declared shall not appear in the initializer expression. [...]

Sign up to request clarification or add additional context in comments.

1 Comment

yeah g++ diagnostics pale in front of clang. I should've known this. thanks!
2

Type deduction doesn't work for constructors. auto will deduce the type for the expression, yes, but new Handler() requires explicit type. Write a factory function instead:

// also don't use raw owning pointers
template <typename L>
std::unique_ptr<Handler<L>> make_handler(L lambda) {
    return std::unique_ptr<Handler<L>>(new Handler<L>(lambda));
}

Sure, it's repeating yourself a bit, but only once. Then you can do

auto l1 = make_handler([](...) { ... });
auto l2 = make_handler([](...) { ... });

and it'll work fine.

3 Comments

This is not the only problem, though. The other is that auto declared variables can't be used in their own initializer.
i agree, the problem seems to be using l1 inside l1 initialization. Even after solving these problems i get more errors
Template argument deduction does work for constructors, but only to deduce the constructor arguments, not the type being constructed

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.