7

I have succeeded writing a class like this one, capturing this in a lambda defined as non-static attribute of said class:

#include <memory>
#include <iostream>
#include <functional>

struct S
{
  S()
  {
    std::cout << "S::S()[" << this << "]" << std::endl;
  }

  std::string y_{"hi mate"};
  int x_;
  std::function<void(int*)> del_{[this](int *ptr)
  {
    std::cout << "Deleting ptr[" << ptr << "] this[" << this << "] this->y_[" << this->y_ << "]" << std::endl;
  }};
  std::unique_ptr<decltype(x_), decltype(del_)> unique_{&x_, del_};
};

int main()
{
  S s;
}

This compiles and seems to run just fine.

However, with a templated class, it doesn't work anymore:

#include <memory>
#include <iostream>
#include <functional>

template <typename>
struct S
{
  S()
  {
    std::cout << "S::S()[" << this << "]" << std::endl;
  }

  std::string y_{"hi mate"};
  int x_;
  std::function<void(int*)> del_{[this](int *ptr)
  {
    std::cout << "Deleting ptr[" << ptr << "] this[" << this << "] this->y_[" << this->y_ << "]" << std::endl;
  }};
  std::unique_ptr<decltype(x_), decltype(del_)> unique_{&x_, del_};
};

int main()
{
  S<int> s;
}

$> g++ -std=c++1y custom_deleter_template.cpp
~/test custom_deleter_template.cpp: In instantiation of ‘struct S::’: custom_deleter_template.cpp:9:3: required from ‘S< >::S() [with = int]’ custom_deleter_template.cpp:24:10:
required from here custom_deleter_template.cpp:15:35: internal compiler error: in tsubst_copy, at cp/pt.c:12569
std::function del_{[this](int *ptr) ^ Please submit a full bug report, with preprocessed source if appropriate. See for instructions. Preprocessed source stored into /tmp/pyro/ccxfNspM.out file, please attach this to your bugreport.

Before filing a bugreport (which I can't do, they blocked account creation), is it normal that it does not compile, based on what the standard says?

Compiler is g++ (Ubuntu 4.9.2-0ubuntu1~14.04) 4.9.2, used flag -std=c++1y. Same thing happens with flag -std=c++11.

pyro
  • 73
  • 5

1 Answers1

0

This is indeed a bug in GCC, which is already being tracked.

It seems to affect 4.8 and 4.9. As pointed out in the comments this particular example works fine for 4.7 and 5.0. You can see that for yourself here and play with the different versions of gcc.

However this reduced version of your code with no external dependency still crashes with 5.0:

template <typename>
struct S {
  int f{[this](){return 42;}()};
};

int main(){
    return S<int>{}.f; //  should return 42
}

I would suggest that you wait for the bug I referenced to be fixed before using your code, or switch to another compiler ;).

Thibaut
  • 2,400
  • 1
  • 16
  • 28
  • Your code is invalid, and rejected by clang because `Lambda` is an empty struct and doesn't have any room for storing anything, including the lambda you're passing. It would probably be useful to check if a valid program (just give `Lambda` a templated constructor that does nothing) fails the same way. –  Mar 07 '15 at 10:22
  • @hvd: You are right about the code being ill formatted, but that is besides the point, GCC should reject it as well, not segfault. This indicates the frontend still has some issues dealing with lambdas in a template context. – Thibaut Mar 07 '15 at 10:39
  • Sure, but it would be a lesser issue if the ice-on-valid is fixed, and only an ice-on-invalid remains, than if there is still an ice-on-valid issue. –  Mar 07 '15 at 10:43
  • @hvd: fair enough, I updated the example, it still triggers the same error but is now valid. – Thibaut Mar 07 '15 at 10:45
  • @hvd: interesting. I get an error in 20150306: http://melpon.org/wandbox/permlink/aDgR5Sev834bhMHd – Thibaut Mar 07 '15 at 10:50
  • How odd. Testing shows that in GCC 5 (20150220), that gives an ICE with `-std=c++14`, but not with `-std=c++11`. In GCC 4.9, it gives an ICE with either `-std=c++11` or `-std=c++14`. –  Mar 07 '15 at 10:50
  • Yeah, I noticed that I messed up my testing. :) –  Mar 07 '15 at 10:51
  • @hvd: it seems to fail on HEAD for `c++14`, `c++1y` and `c++1z`. – Thibaut Mar 07 '15 at 10:52