title: Using friend functions to retrieve type information from a polymorphic class?
body: <p>I have a question about using friend functions inside a nested polymorphic class to retrieve type information.</p>
  
  <p>I have the following code which demonstrates what I'm doing. Given two classes, <code>A&lt;T&gt;</code> and <code>B&lt;T&gt;</code>, I can create a runtime polymorphic wrapper that holds an <code>A</code> or <code>B</code>. In practice, this wrapper could hold anything, including another templated class that has a similar static interface.</p>
  
  <pre><code>template&lt;typename T&gt;
  struct A {
    T value_;
  
    A(T value) : value_(value) {}
  
    void sayHello() const {
      std::cout &lt;&lt; "Hello from A! " &lt;&lt; value_ &lt;&lt; '\n';
    }
  };
  
  template&lt;typename T&gt;
  struct B {
    T value_;
  
    B(T value) : value_(value) {}
  
    void sayHello() const {
      std::cout &lt;&lt; "Hello from B! " &lt;&lt; value_ &lt;&lt; '\n';
    }
  };
  </code></pre>
  
  <p>The wrapper comes from Sean Parent's Runtime Polymorphism concepts, but I have a need to retrieve the type information for some operations. For example, maybe I can add an <code>A</code> and a <code>B</code>, but not an <code>A</code> and a <code>C</code>. Basically, if I place a friend function within the templated wrapper class, I can cast the object back to its original type.</p>
  
  <pre><code>class Wrapper {
  private:
    class Concept {
    public:
      virtual ~Concept() = default;
  
      virtual void sayHello() const = 0;
    };
  
    template&lt;typename T&gt;
    class Model final
        : public Concept {
    private:
      T data_;
  
    public:
      Model(T data) : data_(data) {}
  
      virtual void sayHello() const override {
        data_.sayHello();
      }
  
    private:
      template&lt;typename U&gt;
      friend inline void doSomething(const Concept &amp;lhs, const B&lt;U&gt; &amp;rhs) {
        T x = static_cast&lt;const Model&lt;T&gt; &amp;&gt;(lhs).data_;
  
        x.sayHello();
        rhs.sayHello();
  
        auto y = x.value_ + rhs.value_;
  
        std::cout &lt;&lt; y &lt;&lt; '\n';
      }
    };
  
    template&lt;typename U&gt;
    friend inline void doSomething(const Concept &amp;lhs, const B&lt;U&gt; &amp;rhs);
  
    std::shared_ptr&lt;const Concept&gt; ptr_;
  
  public:
    template&lt;typename T&gt;
    explicit inline Wrapper(T a)
        : ptr_(std::make_shared&lt;Model&lt;A&lt;T&gt;&gt;&gt;(std::move(a))) {}
  
    template&lt;typename U&gt;
    friend inline void someFriend(Wrapper &amp;lhs, B&lt;U&gt; &amp;rhs) {
      doSomething(*lhs.ptr_, rhs);
    }
  };
  </code></pre>
  
  <p>Note that I'm able to <code>static_cast</code> the <code>Concept</code> class within the friend function because its type can be deduced from within the context of the <code>Model&lt;T&gt;</code> class.</p>
  
  <p>So I can use the code like this:</p>
  
  <pre><code>Wrapper a(1);
  B&lt;int&gt; b{2};
  
  someFriend(a, b);
  </code></pre>
  
  <p>Which outputs:</p>
  
  <pre><code>Hello from A! 1
  Hello from B! 2
  3
  </code></pre>
  
  <p>My question is whether there is some kind of unforeseen problem doing things this way. Also, if I replace the object held in the pointer, should the <code>static_cast</code> still work? </p>
  
  <p>Some preliminary tests I've run show that it's fairly reliable, but I occasionally run into the problem that the call seems to 'specialize' around the first object and then doesn't switch if the pointer changes to a new object.</p>
  
  <p><a href="https://ideone.com/yqOBpH" rel="nofollow noreferrer">Here</a> is a link to the code.</p>