I have the following snippet which has an object with a compile-time value:
template <int V>
struct Value
{
constexpr Value() = default;
constexpr int value() const { return V; }
};
int main()
{
Value<1> v;
static_assert(v.value(), ""); // OK
auto l = [=]()
{
static_assert(v.value(), ""); // Error
};
(void)l;
}
The problem is in the static_assert within the lambda. It passes on gcc 6.4, 10.1 but fails on 7.1 and 8.1. The first assert (outside of the lamda) passes on all of them. If changed to constexpr Value<1> v;, it starts passing on 7.1 but not 8.1. I was wondering why this is happening.
Demo:
https://godbolt.org/z/4z7vdKGMq
gcc 8.1 contained a compiler bug that prevented lambda captures from being constexpr:
Bug 86429 - [8 Regression] lambda capture breaks constexpr-ness
It was fixed in 8.4, but not backported to previous versions. So gcc versions 8.1 - 8.3 still contain this bug, preventing the captured v from being treated as constexpr.
For 7.1 i'm not 100% sure since i didn't manage to find a bug for it; but given that it rejects some constructs even with constexpr my guess would be that it is a precursor-bug to the 8.1 one that just happend to remain unnoticed.
It fails with exactly the same error message - '__closure' is not a constant expression - if an explicit capture clause is used:
godbolt
constexpr Value<1> v;
static_assert(v.value(),""); // OK
auto l = [v]() {
static_assert(v.value(),""); // OK (Error in 7.1)
};
auto l2 = [&v]() {
static_assert(v.value(),""); // OK (Error in 7.1)
};
auto l3 = [=]() {
static_assert(v.value(),""); // OK
};
auto l4 = [&]() {
static_assert(v.value(),""); // OK
};
Related
Sometimes for algebraic types it is convenient to have a constructor that takes a literal value 0 to denote the neutral element, or 1 to denote the multiplicative identity element, even if the underlying type is not an integer.
The problem is that it is not obvious how to convince the compiler only to accept, 0 or 1 without accepting any other integer.
Is there a way to do this in C++14 or beyond, for example combining literals, constexpr or static_assert?
Let me illustrate with a free function (although the idea is to use the technique for a constructor that take a single argument. Contructors cannot take template parameters either).
A function that accepts zero only could be written in this way:
constexpr void f_zero(int zero){assert(zero==0); ...}
The problem is that, this could only fail at runtime. I could write f_zero(2) or even f_zero(2.2) and the program will still compile.
The second case is easy to remove, by using enable_if for example
template<class Int, typename = std::enable_if_t<std::is_same<Int, int>{}> >
constexpr void g_zero(Int zero){assert(zero==0);}
This still has the problem that I can pass any integer (and it only fails in debug mode).
In C++ pre 11 one had the ability to do this trick to only accept a literal zero.
struct zero_tag_{};
using zero_t = zero_tag_***;
constexpr void h_zero(zero_t zero){assert(zero==nullptr);}
This actually allowed one to be 99% there, except for very ugly error messages.
Because, basically (modulo Maquevelian use), the only argument accepted would be h_zero(0).
This is situation of affairs is illustrated here https://godbolt.org/z/wSD9ri .
I saw this technique being used in the Boost.Units library.
1) Can one do better now using new features of C++?
The reason I ask is because with the literal 1 the above technique fails completely.
2) Is there an equivalent trick that can be applied to the literal 1 case? (ideally as a separate function).
I could imagine that one can invent a non-standard long long literal _c that creates an instance of std::integral_constant<int, 0> or std::integral_constant<int, 1> and then make the function take these types. However the resulting syntax will be worst for the 0 case. Perhaps there is something simpler.
f(0_c);
f(1_c);
EDIT: I should have mentioned that since f(0) and f(1) are potentially completely separate functions then ideally they should call different functions (or overloads).
In C++20 you can use the consteval keyword to force compile time evaluation. With that you could create a struct, which has a consteval constructor and use that as an argument to a function. Like this:
struct S
{
private:
int x;
public:
S() = delete;
consteval S(int _x)
: x(_x)
{
if (x != 0 && x != 1)
{
// this will trigger a compile error,
// because the allocation is never deleted
// static_assert(_x == 0 || _x == 1); didn't work...
new int{0};
}
}
int get_x() const noexcept
{
return x;
}
};
void func(S s)
{
// use s.get_x() to decide control flow
}
int main()
{
func(0); // this works
func(1); // this also works
func(2); // this is a compile error
}
Here's a godbolt example as well.
Edit:
Apperently clang 10 does not give an error as seen here, but clang (trunk) on godbolt does.
You can get this by passing the 0 or 1 as a template argument like so:
template <int value, typename = std::enable_if_t<value == 0 | value == 1>>
void f() {
// Do something with value
}
The function would then be called like: f<0>(). I don't believe the same thing can be done for constructors (because you can't explicitly set template parameters for constructors), but you could make the constructor(s) private and have static wrapper functions which can be given template parameters perform the check:
class A {
private:
A(int value) { ... }
public:
template <int value, typename = std::enable_if_t<value == 0 || value == 1>>
static A make_A() {
return A(value);
}
};
Objects of type A would be created with A::make_A<0>().
Well... you have tagged C++17, so you can use if constexpr.
So you can define a literal type when 0_x is a std::integral_constant<int, 0> value, when 1_x is a std::integral_constant<int, 1> and when 2_x (and other values) gives a compilation error.
By example
template <char ... Chs>
auto operator "" _x()
{
using t0 = std::integer_sequence<char, '0'>;
using t1 = std::integer_sequence<char, '1'>;
using tx = std::integer_sequence<char, Chs...>;
if constexpr ( std::is_same_v<t0, tx> )
return std::integral_constant<int, 0>{};
else if constexpr ( std::is_same_v<t1, tx> )
return std::integral_constant<int, 1>{};
}
int main ()
{
auto x0 = 0_x;
auto x1 = 1_x;
//auto x2 = 2_x; // compilation error
static_assert( std::is_same_v<decltype(x0),
std::integral_constant<int, 0>> );
static_assert( std::is_same_v<decltype(x1),
std::integral_constant<int, 1>> );
}
Now your f() function can be
template <int X, std::enable_if_t<(X == 0) || (X == 1), bool> = true>
void f (std::integral_constant<int, X> const &)
{
// do something with X
}
and you can call it as follows
f(0_x);
f(1_x);
For the case of Ada, you can define a subtype, a new type, or a derived type that is constrained only for the values of Integer 0 and 1.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure two_value is
-- You can use any one of the following 3 declarations. Just comment out other two.
--subtype zero_or_one is Integer range 0 .. 1; -- subtype of Integer.
--type zero_or_one is range 0 .. 1; -- new type.
type zero_or_one is new Integer range 0 .. 1; -- derived type from Integer.
function get_val (val_1 : in zero_or_one) return Integer;
function get_val (val_1 : in zero_or_one) return Integer is
begin
if (val_1 = 0) then
return 0;
else
return 1;
end if;
end get_val;
begin
Put_Line("Demonstrate the use of only two values");
Put_Line(Integer'Image(get_val(0)));
Put_Line(Integer'Image(get_val(1)));
Put_Line(Integer'Image(get_val(2)));
end two_value;
upon compiling you get the following warning message, although compiles successfully :
>gnatmake two_value.adb
gcc -c two_value.adb
two_value.adb:29:40: warning: value not in range of type "zero_or_one" defined at line 8
two_value.adb:29:40: warning: "Constraint_Error" will be raised at run time
gnatbind -x two_value.ali
gnatlink two_value.ali
And executing it gives the runtime error as specified by the compiler
>two_value.exe
Demonstrate the use of only two values
0
1
raised CONSTRAINT_ERROR : two_value.adb:29 range check failed
So, basically you can constrain the values by defining the new types, derived types or subtypes, you don't need to include the code to check the range, but based on your data type the compiler will automatically warn you.
This isn't a modern solution, but adding on to Zach Peltzer's solution, you can keep your syntax if you use macros...
template <int value, typename = std::enable_if_t<value == 0 | value == 1>>
constexpr int f_impl() {
// Do something with value
return 1;
}
#define f(x) f_impl<x>()
int main() {
f(0); //ok
f(1); //ok
f(2); //compile time error
}
Though, with the constructor problem you could just make the class templated instead of trying to have a templated constructor
template<int value, typename = std::enable_if_t<value == 0 | value == 1>>
class A {
public:
A() {
//do stuff
}
};
int main() {
A<0> a0;
auto a1 = A<1>();
// auto a2 = A<2>(); //fails!
}
The best solution to accept literal 0 that I've found to date is to use std::nullptr_t as the function's input:
struct math_object
{
real x,y,z;
math_object(std::nullptr_t) : x(0), y(0), z(0) {}
};
This has conversion advantages over some of the other solutions. For example, it allows syntax such as.. void MyFunc(const math_object &obj=0); I've been using this for years, and haven't found any trouble. However, I do not have a similar solution for literal 1. For that, I created a construct::id structure that has a global IDENTITY variable.
There's a basic problem. How can you do that in the compiler to be done for a parameter, and at the same time be efficient? Well, what do you need exactly?
That is included in strong typed languages like Pascal, or Ada. The enumerated types have only a couple of values, and the types are normally checked at development, but otherwise, the checks are eliminated by some compiler option at runtime, because just everything goes well.
A function interface is a contract. It is a contract between a seller (the writer of the function) and a buyer (the user of that function). There's even an arbiter, which is the programming language, that can act upon if someone tries to cheat the contract. But at the end, the program is being run in a machine that's open to make arbitraryness like modifying the set of enumerated values and put in the place a completely (and not permitted value).
The problem comes also with separate compilation. Separate compilation has its drawbacks, as it must face a compilation, without having to recheck and retest all previous compilations you have made. Once a compilation is finished, everything you have put in the code is there. If you want the code to be efficient, then the tests are superfluous, because caller and implementer both cope with the contract, but if you want to catch a lyer, then you have to include the test code. And then, it is better to do once for all cases, or is it better to let the programmer decide when and when not we want to catch a lyer?
The problem with C (and by legacy with C++) is that they were inspired by very good programmers, that didn't mistakes, and that have to run their software in big and slow machines. They decided to make both languages (the second was for interoperability purposes) weak typed... and so they are. Have you tried to program in Ada? or Modula-2? You'll see that, over the time, the strong typing thing is more academic than otherwise, and finally what you want, as a professional, is to have the freedom to say: now I want to be safe (and include test code), and now I know what I'm doing (and please be most efficient as you can)
Conclusion
The conclussion is that you are free to select the language, to select the compiler, and to relax the rules. The compilers have the possibility to allow you that. And you have to cope with it, or invent (this is something that todays happens almost each week) your own programming language.
This is the answer to my question, based on #IlCapitano answer for a wrapper class.
This wrapper class can be made private an used only on the construction.
class Matrix {
struct ZeroOROne {
/*implicit*/ consteval ZeroOROne(int n) : val_{n} {
if (n != 0 and n != 1) {throw;} // throw can produce an error at compile time
}
int val_;
};
public:
constexpr Matrix(ZeroOROne _0_or_1) {
if(_0_or_1.val_ == 0) { // this cannot be if constexpr, but that is ok
a00 = a01 = a10 = a11 = 0.0;
new int{0}; // allocation could is ok here
} else {
a00 = a11 = 1.0;
a10 = a01 = 0.0;
new int{0}; // allocation could is ok here
}
}
double a00; double a01;
double a10; double a11;
};
In this way, only Matrix A(0) or Matrix A(1) are allowed.
(Although it works with constant variables as well, but that is ok.)
int main() {
// ZeroOROne(0);
// ZeroOROne(1);
// ZeroOROne(2); // compilation error
Matrix A(0);
Matrix B(1);
// Matrix C(2); // compilation error
int const d = 0; // this works because the compiler can "see" the 0.
Matrix D(d);
constexpr int e = 0;
Matrix E(e);
// int f = 0;
// Matrix F(f); // compile error
return B.a00;
}
Here it is shown that the "runtime" if in the constructor is not a problem and can be elided by the compiler: https://godbolt.org/z/hd6TWY6qW
The solution needs C++20 and it works in recent version of GCC and clang.
I have tried to create a compile-time simple Key-Value map in C++. I'm compiling with /std:c++11.
(Using IAR compiler for embedded code and only cpp++11 is supported at the moment)
I've learnt a little bit about meta-programming.
I don't want my map to have a default value, if key is not found,
like this post: How to build a compile-time key/value store?
I want to get compiler error, if in my code I'm trying to get a value which is not stored in the map.
Here is what I've done:
#include <iostream>
template <int kk, int vv>
struct KeyValue
{
static const int k = kk, v = vv;
};
// Declaration
template <typename kv, typename...>
struct CompileTimeMap;
// Recursive Definition
template<typename kv, typename... rest>
struct CompileTimeMap<kv, rest...>
{
template<int k_input>
struct get
{
static const int val = (k_input == kv::k) ? kv::v : CompileTimeMap<rest...>::get<k_input>::val;
};
};
// Base Definition
template <typename kv>
struct CompileTimeMap<kv>
{
template<int k_input>
struct get
{
static const int val = (k_input == kv::k) ? kv::v;
};
};
// ----------------------------- Main -----------------------------
typedef CompileTimeMap<KeyValue<10, 20>, KeyValue<11, 21>, KeyValue<23, 7>> mymap;
int main()
{
// This calles should be ok !! :)
std::cout << mymap::get<10>::val << std::endl;
std::cout << mymap::get<11>::val << std::endl;
std::cout << mymap::get<23>::val << std::endl;
// This line should resolve a compile error !! (there is no key of 33)
std::cout << mymap::get<33>::val << std::endl;
}
I get the following error: error C2131: expression did not evaluate to a constant.
How can I make this work? Many thanks :)
Don't write a template metaprogram, where it is not necessary. Try this simple solution (CTMap stands for compile time map):
template <class Key, class Value, int N>
class CTMap {
public:
struct KV {
Key key;
Value value;
};
constexpr Value operator[] (Key key) const
{
return Get (key);
}
private:
constexpr Value Get (Key key, int i = 0) const
{
return i == N ?
KeyNotFound () :
pairs[i].key == key ? pairs[i].value : Get (key, i + 1);
}
static Value KeyNotFound () // not constexpr
{
return {};
}
public:
KV pairs[N];
};
constexpr CTMap<int, int, 3> ctMap {{ { 10, 20 }, { 11, 21 }, { 23, 7 } }};
static_assert (ctMap[10] == 20, "Error.");
static_assert (ctMap[11] == 21, "Error.");
static_assert (ctMap[23] == 7, "Error.");
// constexpr auto compilationError = ctMap[404];
You will get a compilation error, if you uncomment the last line (live demo). The compiler will direct you to the KeyNotFound () : line, from
which the reason of the failure should be obvious.
Remarks
The member variable pairs is made public, to make it possible to initialize the map with list-initialization.
The given N and the number of pairs that initialize CTMap should match. If N is less, you get a compilation error. If N is greater, zero-initialized pairs ({ 0, 0 }) will be silently added to pairs. Pay attention to this.
The (compiler generated) constructor does not check for duplicate keys. operator[] will find the first, but the intended usage is that you do not initialize CTMap with duplicate keys.
Recursion is not necessary in C++14. We can write a for loop in a constexpr function (live demo). The linked implementation gives another idea for giving a compiler error in case the key is not found: an exception is thrown. The member variable pairs is made private.
Intended to be used in compile time
This is a linear map, and parameters are passed by value. My intention was that the map will be used in compile time evaluated code, where this should not be a problem.
Note also that when evaluated in run time, this class won't give any feedback if the key is not found in the map.
Let's take a closer look of how ctMap[10] works in different situations. I have tried the following with three compilers (MSVC v19.24, clang 10.0.0, gcc 9.3).
constexpr int C = ctMap[10]; – The global constant C will be initialized with 20 even in debug builds. No computation is made during run-time. Note that to ensure, that the global will be created, you have to take its address somewhere. If you use the value of C, its value (20) will be substituted where it is used, and C won't be created in the object file even in debug builds.
int Foo () { return ctMap[10]; } – In debug builds operator[] will be called. In release builds MSVC inlines operator[] to Foo, i.e. eliminates one call, but the resulting code has linear complexity (the compiler is not forced to do the computation in compile time, and code optimization is poor in MSVC). Clang and gcc compiles a return 20;.
And this is how ctMap[404] works (with the same three compilers):
constexpr int C = ctMap[404]; – Does not compile, as mentioned above.
int Foo () { return ctMap[404]; } – The same remarks apply as for ctMap[10], but Foo will return 0. You cannot know, that 404 was not in the map. To get the compilation error, Foo has to be constexpr and forced to be evaluated in compile time by e.g. assigning it to a constexpr variable or an enumerator, using it in a template argument, as a size of a C array, in a static_assert, etc.
(this question was inspired by How can I generate a compilation error to prevent certain VALUE (not type) to go into the function?)
Let's say, we have a single-argument foo, semantically defined as
int foo(int arg) {
int* parg;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
The whole code above is used to illustrate a simple idea - function returns it's own argument unless the argument is equal to 5, in which case behavior is undefined.
Now, the challenge - modify the function in such a way, that if it's argument is known at compile time, a compiler diagnostic (warning or error) should be generated, and if not, behavior remains undefined in runtime. Solution could be compiler-dependent, as long as it is available in either one of the big 4 compilers.
Here are some potential routes which do not solve the problem:
Making function a template which takes it's argument as a template parameter - this doesn't solve the problem because it makes function ineligible for run-time arguments
Making function a constexpr - this doesn't solve the problem, because even when compilers see undefined behavior, they do not produce diagnostics in my tests - instead, gcc inserts ud2 instruction, which is not what I want.
I got error with constexpr when used in constant expression for:
constexpr int foo(int arg) {
int* parg = nullptr;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
Demo
We cannot know that argument value is known at compile type, but we can use type representing value with std::integral_constant
// alias to shorten name.
template <int N>
using int_c = std::integral_constant<int, N>;
Possibly with UDL with operator "" _c to have 5_c, 42_c.
and then, add overload with that:
template <int N>
constexpr auto foo(int_c<N>) {
return int_c<foo(N)>{};
}
So:
foo(int_c<42>{}); // OK
foo(int_c<5>{}); // Fail to compile
// and with previous constexpr:
foo(5); // Runtime error, No compile time diagnostic
constexpr auto r = foo(5); // Fail to compile
As I said, arguments are not known to be constant inside the function, and is_constexpr seems not possible in standard to allow dispatch, but some compiler provide built-in for that (__builtin_constant_p), so with MACRO, we can do the dispatch:
#define FOO(X) [&](){ \
if constexpr (__builtin_constant_p(X)) {\
return foo(int_c<__builtin_constant_p (X) ? X : 0>{});\
} else {\
return foo(X); \
} \
}()
Demo
Note: Cannot use foo(int_c<X>{}) directly, even in if constexpr, as there is still some syntax check.
gcc/clang/intel compilers support __builtin_constant_p, so you can use something like that:
template <int D>
int foo_ub(int arg) {
static_assert(D != 5, "error");
int* parg = nullptr;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
#define foo(e) foo_ub< __builtin_constant_p(e) ? e : 0 >(e)
these statements produce compile time error:
foo(5)
foo(2+3)
constexpr int i = 5; foo(i);
while all others - runtime segfault (or ub if no nullptr is used)
It's not perfect and it requires us to use arguments in two different places, but it 'works':
template<int N = 0>
int foo(int arg = 0) {
static_assert(N != 5, "N cannot be 5!");
int* parg;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
We can call it like so:
foo<5>(); // does not compile
foo(5); // UB
foo<5>(5); // does not compile
foo<5>(10); // does not compile
foo<10>(5); // UB
foo(); // fine
foo<10>(); // fine
foo(10); // fine
Consider the following snippet trimmed down to illustrate the problem:
#include <cstdio>
struct A {
union {
struct { int a0, a1; } aa;
int bb[2];
};
#if 1 //bug
constexpr A(int a0, int a1) : aa{a0, a1} {}
#else //OK
constexpr A(int a0, int a1) : bb{a0, a1} {}
#endif
};
int main() {
A t0{2, 3}; std::printf("%d %d\n", t0.aa.a0, t0.aa.a1); //2 3 (OK)
static A t1{2, 3}; std::printf("%d %d\n", t1.aa.a0, t1.aa.a1); //2 3 (OK)
constexpr A t2{2, 3}; std::printf("%d %d\n", t2.aa.a0, t2.aa.a1); //2 3 (OK)
static constexpr A t3{2, 3}; std::printf("%d %d\n", t3.aa.a0, t3.aa.a1); //0 0 (??)
}
msvc 2015 update 3 and 2017 rc1 silently generate incorrect code by zero-initializing t3 instead of properly initializing it with the given values. gcc and clang are fine.
I looked into reporting a bug but it is too much hassle (I don't use the IDE). If you care, please confirm this is a bug, and let it be known to whom it may concern at microsoft.
I can reproduce this on VS 2015, with both the x86-32 and x86-64 compilers.
I can also confirm that current versions of GCC, Clang, and ICC compile it correctly. Nor can I find anything in the language standard that prohibits what you're doing. The implementation is allowed some leeway in whether it initializes the object at compile-time (as you would expect) or at run-time, but MSVC isn't initializing it at all.
As might be expected, the same problem is observed when the object's declaration is moved to namespace scope, e.g.:
#include <cstdio>
struct A {
union {
struct { int a0, a1; } aa;
int bb[2];
};
constexpr A(int a0, int a1) : aa{a0, a1} { }
};
namespace {
constexpr A t3 { 2, 3 };
};
int main() {
std::printf("%d %d\n", t3.aa.a0, t3.aa.a1);
}
…as well as if the object is declared as a static member of an otherwise empty struct.
Although the visible effect is a zero-initialization, that does not actually appear to be what the compiler is doing. Rather, it fails to emit a value at all in the corresponding data segment, so when the code attempts to load a value from that address to push onto the stack when making the call to printf, it ends up pushing a zero.
It seems that the union here is key to reproducing the bug. If A contains only the struct aa, then there is no problem. Simply removing bb to leave a one-member union also solves the problem.
Note that you have everything you need here to submit a bug report to Microsoft for the VS 2017 compiler (use of the IDE is not required). The code included in the question is a self-contained example that demonstrates the problem perfectly well. If you really don't want to do it yourself, let me know and I'll submit the bug.
Below code fails with BAD_ACCESS when I call s_capture_void_int() in the last line and I do not understand why. I suppose that when I assign lambda expression to a global variable it supposed to copy itself together with captured values. So in my understanding dangling references should not appear. But it looks like I'm missing something.
std::function<void()> s_capture_void_int;
void capture_void_int (const std::function<void(int)>& param)
{
s_capture_void_int = [param]() {
param(1);
};
}
void capture_local_lambda()
{
auto local_lambda = [](int) {
};
s_capture_void_int = [local_lambda]() {
local_lambda(1);
};
}
BOOST_AUTO_TEST_CASE( test_lambda_captures )
{
//Case 1: this works
auto func2 = [](int){};
{
std::function<void(int)> func2_fn(func2);
s_capture_void_int = [func2_fn]() { func2_fn(1); };
}
s_capture_void_int();
//case 2: even this works.
capture_local_lambda();
s_capture_void_int();
//case 3: but this fails.
auto func3 = [](int){};
{
std::function<void(int)> func3_fn(func3);
capture_void_int(func3_fn);
}
s_capture_void_int(); //<- it crashes here
}
I don't understand two things here:
If crash happen because of func3_fn goes out of scope then why case 1
and 2 works?
If I change this code to std::function (note no parameter) then it works ok. Could it be a compiler bug?
For anybody who come across same problem. This is indeed a compiler bug and I found simple and stupid workaround. Workaround is not tested but at least my program does not segfault right away on a first call to std::function.
Problem manifest itself with clang shipped with Xcode 5.0.2 and 5.1 compiler. gcc 4.8 and possibly stock clang does not have this problem. Simplest possible program to trigger problem:
#include <iostream>
#include <functional>
std::function<void()> buggy_function;
/*
void workaround (const std::function<void(int)>& param)
{
auto a = [&,param]() {
param(1);
};
}
*/
void trigger_bug (const std::function<void(int)>& param)
{
buggy_function = [&,param]() {
param(1);
};
}
int main(int argc, const char * argv[])
{
auto func3 = [](int){};
std::function<void(int)> func3_fn(func3);
trigger_bug(func3_fn);
buggy_function();
return 0;
}
If you uncomment 'workaround' function it magically start working. Order of functions is important, workaround function have to be before any other functions using std::function. If you put 'workaround' below 'trigger_bug' then it stop working.
I'd say it's a compiler bug. It works fine in GCC. Perhaps the param in capture_void_int is incorrectly captured by reference (since it's a reference) when it should instead be captured by value.