In C++, is it possible to check (preferably at compile time) if a function argument reference value is thread-local?
E.g.
void foo( int& bar ) { ... }
I'd like to check/enforce that bar refer to a thread_local.
Assume C++17 or later on Windows and/or Fedora.
template<class T, auto Key>
struct thread_local_decl_t;
template<class T>
struct thread_local_t {
template<class, auto>
friend struct thread_local_decl_t;
operator T&() noexcept {
return get();
}
operator T const&() const noexcept {
return get_const();
}
private:
T&(*gettor)() = nullptr;
thread_local_t(T&(*gettor_arg)()):
gettor(gettor_arg)
{}
T& get() { return gettor(); }
T const& get_const() const { return gettor(); }
};
template<class T, auto Key>
struct thread_local_decl_t:
thread_local_t<T>
{
public:
static T& get_ctor(std::function<T()> ctor) {
thread_local T t{ctor()};
return t;
}
static T& get() {
return get_ctor(nullptr);
}
static T const& get_const() {
return get(nullptr);
}
template<class...Args>
explicit thread_local_decl_t(Args&&...args):
thread_local_t<T>(&thread_local_decl_t::get)
{
// construct the thread-local
get_ctor( [&]()->T{ return T(std::forward<Args>(args)...); } );
}
thread_local_decl_t(thread_local_decl_t const&)=default;
thread_local_decl_t(thread_local_decl_t &&)=default;
};
#define THREAD_LOCAL(...) \
thread_local_decl_t< __VA_ARGS__, []{} >
void print( thread_local_t<int> x ) {
std::cout << x << "\n";
}
void test() {
auto tl_int = THREAD_LOCAL(int)( 7 );
print(tl_int);
}
int main() {
test();
}
this bit of evil uses a lambda to create a thread local object within the thread_local_decl_t
that is unique to each use site. We can pass thread local values around and verify they are indeed thread local with the C++ type system by doing a thread_local_t<int>
.
thread_local_t<X>
is a reference to a thread local value, while auto name = THREAD_LOCAL(X)(construction arguments)
declares a thread local value, using this system.
Requires c++20.