News for hackers. Stuff that matters.
Re:C++ Patterns: The Badge by mwkaufma on Tuesday June 11, 2019 @07:14PM (#20160376)
I like it! The self-documentation of where the call is coming-from is quite nice (though a more descriptive name like CallFrom<T> would make that even clearer, were it the principle intent). I can't help myself, though:

    template<typename T>
    Badge<T> FakeBadge() {
      struct Stub {}
      return reinterpret_cast<Badge<T>>(Stub());
    }
Re:C++ Patterns: The Badge by kazinator on Tuesday June 11, 2019 @07:38PM (#20160504)
Doesn't subvert Device badges for me. Complete sample:

  template<typename T>
  class Badge {
      friend T;
      Badge() {}
  };

  template<typename T>
  Badge<T> FakeBadge() {
    struct Stub {};
    return reinterpret_cast<Badge<T>>(Stub());
  };

  class Device {
  public:
    static Badge<Device> getBadge() { return Badge<Device>(); }
  };

  void needDeviceBadge(Badge<Device> badge)
  {
  }

  int main()
  {
     needDeviceBadge(Device::getBadge());   // no error
     needDeviceBadge(FakeBadge<Device>());  // error!
     return 0;
  }
g++ errors:

  badge.cc: In instantiation of ‘Badge<T> FakeBadge() [with T = Device]’:
  badge.cc:25:38:   required from here
  badge.cc:10:10: error: invalid cast from type ‘FakeBadge() [with T = Device]::Stub’ to type ‘Badge<Device>’
     return reinterpret_cast<Badge<T>>(Stub());
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

A reinterpret_cast won't turn an instance of the Stub local class into a Badge<Device>.

That doesn't even have to do with friendship/protection. If we move that line into the Device class, the reinterpret_cast still doesn't compile.

Re:C++ Patterns: The Badge by a1369209993 on Tuesday June 11, 2019 @10:36PM (#20161270)
It does, however, work fine if you use a proper "* (Badge<T>* )&stub" cast.
Re:C++ Patterns: The Badge by kazinator on Wednesday June 12, 2019 @11:50AM (#20165905)
Well, that's a problem in the C++ type system, isn't it; because it (effectively) constructs a value of type Badge<Device>, even though it's not a piece of code sitting in the Device class scope.

The rule should be that if the default constructor of T is not accessible in the scope, then any cast to T * or T & requires a diagnostic. Or something like that.

If I can allocate a suitably aligned buffer of sizeof (T) zeros, and then treat that as a T, I've effectively constructed a T.

Re:C++ Patterns: The Badge by a1369209993 on Wednesday June 12, 2019 @05:36PM (#20169585)
No, that's a good feature of the C++ type system, because it (effectively) allows the programmer to construct a value of type Badge<Device>, even if Device thinks it's okay to prevent that.

It would be better to do eg "return Device::private:get_badge()", but C++ defectively doesn't support that.

Re:C++ Patterns: The Badge by GrayShade on Wednesday June 12, 2019 @04:22AM (#20162718)
Isn't casting unrelated types undefined behavior?
Re:C++ Patterns: The Badge by brianush1 on Wednesday June 12, 2019 @08:26AM (#20163809)
Yes, in the standard it isn't defined, but on most--or maybe even all?--systems and compilers it's perfectly defined, since there is no reason why a compiler would layout two different empty structs in different ways; they're both empty anyways.

Edit: Actually, from reading some of the other comments in the thread, the standard apparently specifies that empty structs are 1 byte in size, so technically they would both be the same size, so casting between them should be fine.

Re:C++ Patterns: The Badge by kazinator on Wednesday June 12, 2019 @12:38PM (#20166504)
It's not defined on systems unless a document spells it out. However, the actual behavior can be deduced to be harmless from black-box testing. compiler source code and generate object code.
Re:C++ Patterns: The Badge by kazinator on Wednesday June 12, 2019 @11:51AM (#20165918)
Problem is that it doesn't require a diagnostic, and the actual behavior of casting one empty struct foo {} to another empty struct bar {} is likely harmless and portable.
Re:C++ Patterns: The Badge by mwkaufma on Tuesday June 11, 2019 @10:56PM (#20161354)
Interesting, I'd always assumed reinterpret_cast<> was YOLO-anything-goes. You learn something every day ;)
Re:C++ Patterns: The Badge by a1369209993 on Tuesday June 11, 2019 @10:33PM (#20161263)
You actually need:

  template<typename T>
  Badge<T> FakeBadge() {
    static struct Stub {} stub;
    return *(Badge<T>*)&stub;
    };
Re:C++ Patterns: The Badge by microtherion on Tuesday June 11, 2019 @07:44PM (#20160528)
That's not a legal C++ cast, but it's conceivable that it could be made to work by casting to a reference type instead.
Re:C++ Patterns: The Badge by vnorilo on Wednesday June 12, 2019 @01:52AM (#20162085)
Badge could prevent this by making the copy and move constructors private.