首页 > 解决方案 > Type Erasure setup C++中的内部类找不到Friend函数

问题描述

我观看了 Klaus Iglberger 在 CppCon 2021 上关于类型擦除的精彩演讲。我根据他的示例自己设置了模式。他的 External Polymorphic 片段被分派给外部类的友元函数。那篇文章不适合我。

我尝试过改变定义的顺序并将友元函数的实现拉到类之外。我还没有设置实现文件,因为我不太相信这会是一个解决方案。

我正在使用 GCC 9.3 和 Clang 10。错误看起来相同。铿锵10: type_erasure_example.cpp:57:22: error: too many arguments to function call, expected 0, have 1 serialize( object );

type_erasure_example.cpp:61:28: error: too many arguments to function call, expected 2, have 3 draw( object, x, y );

GCC9.3:

type_erasure_example.cpp:57:11: error: no matching function for call to ‘Shape::ShapeModel<Square>::serialize(const Square&) const’ 57 | serialize( object );

type_erasure_example.cpp:61:11: error: no matching function for call to ‘Shape::ShapeModel<Square>::draw(const Square&, int&, int&) const’ 61 | draw( object, x, y );

#include <iostream>
#include <memory>
#include <vector>

class Circle 
{ 
 public: 
   explicit Circle( double rad ) 
      : radius{ rad } 
      // ... Remaining data members 
   {} 
   double getRadius() const noexcept { return radius; }
   // ... getCenter(), getRotation(), ... 
 private: 
   double radius; 
   // ... Remaining data members 
};

class Square 
{ 
 public: 
   explicit Square( double s ) 
      : side{ s } 
      // ... Remaining data members 
   {} 
   double getSide() const noexcept { return side; }
   // ... getCenter(), getRotation(), ... 
 private: 
   double side; 
   // ... Remaining data members 
};

class Shape 
{ 
 private:
    struct ShapeConcept 
    { 
       virtual ~ShapeConcept() {} 
       virtual void serialize() const = 0; 
       virtual void draw(int x, int y) const = 0; 
       virtual std::unique_ptr<ShapeConcept> clone() const = 0; 
    }; 

    template< typename T > 
    struct ShapeModel : ShapeConcept 
    { 
       ShapeModel( T&& value ) 
          : object{ std::forward<T>(value) } 
       {} 
       
       std::unique_ptr<ShapeConcept> clone() const override 
       { 
          return std::make_unique<ShapeModel>(*this); 
       } 
       void serialize() const override 
       { 
          serialize( object ); // Error
       } 
       void draw( int x, int y ) const override 
       { 
          draw( object, x, y ); // Error
       } 
       T object; 
    };

    friend void serialize( Shape const& shape )
    { 
       shape.pimpl->serialize(); 
    }
    friend void draw( Shape const& shape, int x, int y )
    { 
       shape.pimpl->draw( x, y ); 
    }

    std::unique_ptr<ShapeConcept> pimpl; 
 public: 
   template< typename T > 
   Shape( T&& x ) 
      : pimpl{ new ShapeModel<T>( std::forward<T>(x) ) } 
   {} 
   // Special member functions 
   Shape( Shape const& s ); 
   Shape( Shape&& s ); 
   Shape& operator=( Shape const& s ); 
   Shape& operator=( Shape&& s ); 
};


void serialize( Circle const& circle ) {
    std::cout << "Serializing a circle with radius "
        << circle.getRadius() << std::endl;
} 
void draw( Circle const& circle, int x, int y ) {
    std::cout << "Drawing a circle with radius "
        << circle.getRadius() << " Coordinates ("
        << x << ", " << y << ")" << std::endl;
}
void serialize( Square const& square ) {
    std::cout << "Serializing a square with side "
        << square.getSide() << std::endl;
} 
void draw( Square const& square, int x, int y ) {
    std::cout << "Drawing a square with side "
        << square.getSide() << " Coordinates ("
        << x << ", " << y << ")" << std::endl;
} 

void drawAllShapes( std::vector<Shape> const& shapes ) 
{ 
   for( auto const& shape : shapes ) 
   { 
      draw( shape , 0.0, 0.0 ); 
   } 
}
int main() 
{ 
   using Shapes = std::vector<Shape>; 
   // Creating some shapes 
   Shapes shapes; 
   shapes.emplace_back( Circle{ 2.0 } ); 
   shapes.emplace_back( Square{ 1.5 } ); 
   shapes.emplace_back( Circle{ 4.2 } ); 
   // Drawing all shapes 
   drawAllShapes( shapes ); 
}

标签: c++type-erasureargument-dependent-lookupfriend-function

解决方案


有人在评论中发帖,这让我走上了正轨。我对设置不够了解。朋友班得到了正确的处理。需要重新安排的是免费功能。一个实现文件毕竟会有所帮助,我们可以只做标题:

#include <iostream>
#include <memory>
#include <vector>

class Circle 
{ 
 public: 
   explicit Circle( double rad ) 
      : radius{ rad } 
      // ... Remaining data members 
   {} 
   double getRadius() const noexcept { return radius; }
   // ... getCenter(), getRotation(), ... 
 private: 
   double radius; 
   // ... Remaining data members 
};

class Square 
{ 
 public: 
   explicit Square( double s ) 
      : side{ s } 
      // ... Remaining data members 
   {} 
   double getSide() const noexcept { return side; }
   // ... getCenter(), getRotation(), ... 
 private: 
   double side; 
   // ... Remaining data members 
};

void serialize( Circle const& circle ) {
    std::cout << "Serializing a circle with radius "
        << circle.getRadius() << std::endl;
} 
void draw( Circle const& circle, int x, int y ) {
    std::cout << "Drawing a circle with radius "
        << circle.getRadius() << " Coordinates ("
        << x << ", " << y << ")" << std::endl;
}
void serialize( Square const& square ) {
    std::cout << "Serializing a square with side "
        << square.getSide() << std::endl;
} 

void draw( Square const& square, int x, int y ) {
    std::cout << "Drawing a square with side "
        << square.getSide() << " Coordinates ("
        << x << ", " << y << ")" << std::endl;
} 

class Shape 
{ 
 private:
    struct ShapeConcept 
    { 
       virtual ~ShapeConcept() {} 
       virtual void serialize() const = 0; 
       virtual void draw(int x, int y) const = 0; 
       virtual std::unique_ptr<ShapeConcept> clone() const = 0; 
    }; 

    template< typename T > 
    struct ShapeModel : ShapeConcept 
    { 
       ShapeModel( T&& value ) 
          : object{ std::forward<T>(value) } 
       {} 
       
       std::unique_ptr<ShapeConcept> clone() const override 
       { 
          return std::make_unique<ShapeModel>(*this); 
       } 
       void serialize() const override 
       { 
          ::serialize( object ); 
       } 
       void draw( int x, int y ) const override 
       { 
          ::draw( object, x, y ); 
       } 
       T object; 
    };

    friend void serialize( Shape const& shape )
    { 
       shape.pimpl->serialize(); 
    }
    friend void draw( Shape const& shape, int x, int y )
    { 
       shape.pimpl->draw( x, y ); 
    }

    std::unique_ptr<ShapeConcept> pimpl; 
 public: 
   template< typename T > 
   Shape( T&& x ) 
      : pimpl{ new ShapeModel<T>( std::forward<T>(x) ) } 
   {} 
   // Special member functions 
   Shape( Shape const& s ) = default;
   Shape( Shape&& s ) = default;
   Shape& operator=( Shape const& s ) = default;
   Shape& operator=( Shape&& s ) = default;
};


void drawAllShapes( std::vector<Shape> const& shapes ) 
{ 
   for( auto const& shape : shapes ) 
   { 
      draw( shape , 0.0, 0.0 ); 
   } 
}
int main() 
{ 
   using Shapes = std::vector<Shape>; 
   // Creating some shapes 
   Shapes shapes; 
   shapes.emplace_back( Circle{ 2.0 } ); 
   shapes.emplace_back( Square{ 1.5 } ); 
   shapes.emplace_back( Circle{ 4.2 } ); 
   // Drawing all shapes 
   drawAllShapes( shapes ); 
}

推荐阅读