c++c++17stdthreadthread-local

Check if a function argument value is thread-local


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.


Solution

  • 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 .