Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are both of libstdc++'s constructors for std::thread::id standard compliant?

Tags:

c++

libstdc++

cppreference indicates std::thread::id only has 1 constructor. libstdc++ contains the following additional public constructor:

  explicit id(native_handle_type __id) : _M_thread(__id) { }

Is 'cppreference' out-of-date, or is this constructor not part of the standard? If it's not part of the standard, why would it be public given that std::thread is a friend of std::thread::id?

like image 669
MarkB Avatar asked Sep 02 '25 14:09

MarkB


2 Answers

Standard library implementations are allowed to add any functions, public or otherwise, to any class, so long as they do not interfere with the standard-defined interfaces. Specifically, if some expression would, through overload resolution, call a particular function defined in the standard library, then it must actually call a function causing that behavior. std::thread::id(some_native_handle) would not call the standard-defined id constructor. So it is permissible for the library implementation to have it call something else.

That is, code that should work a certain way by the standard will work that way. Code that wouldn't work might be otherwise permitted to do something, but this is ultimately unspecified and cannot be relied upon across implementations.

like image 199
Nicol Bolas Avatar answered Sep 05 '25 02:09

Nicol Bolas


No, cppreference is not out of date. The constructor is an extension.

Here's the public interface described in the C++23 draft

33.4.3.2 Class thread::id [thread.thread.id]

namespace std {
  class thread::id {
  public:
    id() noexcept;
  };

  bool operator==(thread::id x, thread::id y) noexcept;

  strong_ordering operator<=>(thread::id x, thread::id y) noexcept;

  template<class charT, class traits>
    basic_ostream<charT, traits>&
      operator<<(basic_ostream<charT, traits>& out, thread::id id);

  // hash support
  template<class T> struct hash;
  template<> struct hash<thread::id>;
}

why would it be public given that std::thread is a friend of std::thread::id?

It's also used by the free function this_thread::get_id() and making it public also lets other users of the class use the implementation specific constructor.

  namespace this_thread
  {
    /// this_thread::get_id
    inline thread::id
    get_id() noexcept
    {
#ifndef _GLIBCXX_HAS_GTHREADS
      return thread::id(1);
#elif defined _GLIBCXX_NATIVE_THREAD_ID
      return thread::id(_GLIBCXX_NATIVE_THREAD_ID);
#else
      return thread::id(__gthread_self());
#endif
    }
  }

The LLVM version does not have a similar thread::id constructor. It's simply defined with the constructor required by the standard:

namespace std {
  class thread::id
  {
  public:
    id() noexcept;
  };
}
like image 41
Ted Lyngmo Avatar answered Sep 05 '25 04:09

Ted Lyngmo