Template Template Parameters - Invalid Explicitly Specified Argument

132 views Asked by At

I am just learning how to work with template template parameters and am having trouble invoking a function.

Compiler Error: candidate template ignored: invalid explicitly-specified argument for template parameter 'Container'

My purpose in using the template template approach is to have a very generic composite class that can handle any container type.

For illustration purposes, I am working with Shapes. So I have a ShapeComposite, PolyLine, and a ShapeFactory.

PolyLine extends ShapeComposite and ShapeComposite is where the generic container will live. Can you please help me understand why I am running into this compiler error?

Shape.hpp

class Shape
{
public:
    // just an abstract interface for concrete shapes 
};

ShapeComposite.hpp

template<typename T,template<typename S, typename Alloc> class Container, typename TAlloc = std::allocator<T>>
class ShapeComposite : public Shape
{
private:
    Container<T, TAlloc> shapes;

public:
    ShapeComposite();
    ~ShapeComposite() override = default;

    void addShape(const std::shared_ptr<Shape>& shape);

ShapeComposite.cpp

template<typename T, template<typename S, typename Alloc> class Container, typename TAlloc>
ShapeComposite<T, Container, TAlloc>::ShapeComposite() : shapes{}
{
    // default ctor
}

template<typename T, template<typename S, typename Alloc> class Container, typename TAlloc>
void ShapeComposite<T, Container, TAlloc>::addShape(const std::shared_ptr<Shape>& shape)
{
    shapes.push_back(shape);
}

PolyLine.hpp

template<typename T, template<typename S, typename Alloc> class Container, typename TAlloc = std::allocator<T>>
class PolyLine : ShapeComposite<T, Container, TAlloc>
{
public:
    PolyLine();
    ~PolyLine() override = default;
};

PolyLine.cpp

template<typename T, template<typename S, typename Alloc> class Container, typename TAlloc>
PolyLine<T, Container, TAlloc>::PolyLine() : ShapeComposite<Point, Container, TAlloc>()
{
    // default ctor
}

ShapeFactory.hpp

class ShapeFactory
{
public:
    ShapeFactory() = default;
    virtual ~ShapeFactory() = default;

    virtual Point createStartPoint();
    virtual Point createEndPoint();
    virtual Line createLine() final;

    virtual Point createPoint() = 0;

    template<typename T = Point, template<typename S, typename Alloc> 
    class Container,  typename TAlloc = std::allocator<T>>
    PolyLine<T, Container> createPolyLine();
};

ShapeFactory.cpp

Point ShapeFactory::createStartPoint()
{
    return createPoint();
}

Point ShapeFactory::createEndPoint()
{
    return createPoint();
}

// Template method
Line ShapeFactory::createLine()
{
    Point startPoint = createStartPoint();
    Point endPoint = createEndPoint();
    return Line{startPoint, endPoint};
}

template<typename T, template<typename S, typename Alloc> class Container, typename TAlloc>
PolyLine<T, Container> ShapeFactory::createPolyLine()
{
    PolyLine<T, Container> polyLine ;
    int numLines = 0;

    std::cout << "How many lines would you like to create? ";
    std::cin >> numLines;

    for (int i = 0; i < numLines; ++i)
    {
        Line line = createLine();
        polyLine.addShape(line);
    }
}

ConsoleShapeFactory (just a concrete factory but creating a PolyLine is implemented in the base class)

class ConsoleShapeFactory : public ShapeFactory
{
public:
    ConsoleShapeFactory();
    ~ConsoleShapeFactory() override = default;

    // Function Overrides
    Point createPoint() override;
};

Attempt to create a PolyLine via the ShapeFacotry:

int main()
{
    ConsoleShapeFactory factory;
    factory.createPolyLine<std::list<Point>>()();
}
1

There are 1 answers

1
MSalters On

It seems you're confusing templates and types. std::list is a (class) template. std::list<Point> is an instantiated class template, and therefore a class, and a type.

I can't figure out what you want. Do you want to allow Factory.createPolyLine<std::list<FooBar::Point>>()(); as well? If so, you need to define waht properties a point-like class should have.

It also seems you're defining templates in .cpp files. That can't work; the template body has to be available at the point of instantiation. I.e. Factory.createPolyLine<std::list<Point>>()(); requires not just the declaration, but the whole definition of createPolyLine