I would like to create thread local storage using tbb::enumerable_thread_specific
for elements of type that takes not-const reference in the constructor. Unfortunetly, it does not work from the box, and I have to use std::ref
for construction as a workaround. Here is an example:
#include <tbb/enumerable_thread_specific.h>
struct A {
A(int &) {}
};
int main() {
int i;
// ok
tbb::enumerable_thread_specific<A> ets1(std::ref(i));
// error
tbb::enumerable_thread_specific<A> ets(i);
}
The error is
In file included from /opt/compiler-explorer/libs/tbb/2021.4.0/include/tbb/enumerable_thread_specific.h:17,
from <source>:1:
/opt/compiler-explorer/libs/tbb/2021.4.0/include/oneapi/tbb/enumerable_thread_specific.h: In instantiation of 'void tbb::detail::d1::construct_by_args<T, P>::construct(void*) [with T = A; P = {int&}]':
/opt/compiler-explorer/libs/tbb/2021.4.0/include/oneapi/tbb/enumerable_thread_specific.h:685:31: required from 'void tbb::detail::d1::callback_leaf<Constructor>::construct(void*) [with Constructor = tbb::detail::d1::construct_by_args<A, int&>]'
/opt/compiler-explorer/libs/tbb/2021.4.0/include/oneapi/tbb/enumerable_thread_specific.h:684:10: required from here
/opt/compiler-explorer/libs/tbb/2021.4.0/include/oneapi/tbb/enumerable_thread_specific.h:648:12: error: binding reference of type 'int&' to 'const std::decay<int&>::type' {aka 'const int'} discards qualifiers
648 | new(where) T(args...);
| ^~~~~~~~~~~~~~~~~~~~~
<source>:4:7: note: initializing argument 1 of 'A::A(int&)'
4 | A(int &) {}
| ^~~~~
Online demo: https://godbolt.org/z/qGx7cGz44
It looks like not-const reference becomes const reference inside TBB before it reaches A
constructor. Is it intentional design decision or simply a bug in the implementation?
CodePudding user response:
This has essentially been answered in the comments by 463035818_is_not_an_ai relating it to the same logic behind std::thread, and then linking an answer regarding the same explicit use of ref with threads.
The issue you're encountering with tbb::enumerable_thread_specific and non-const references in constructor arguments is related to the design of tbb::enumerable_thread_specific. The library uses an underlying mechanism to construct and manage instances of the stored type, and this mechanism relies on certain characteristics of the type.
When you provide a non-const reference in the constructor argument, it can create complications in terms of thread safety and object management. enumerable_thread_specific is designed to manage instances of types efficiently across multiple threads, and dealing with non-const references in a thread-safe manner can be challenging.
As you've already figured out you can use std::reference_wrapper or a pointer instead of a non-const reference.