1

I have these two classes:

template <typename GeomType>
class InputCSV
{
public:
    InputCSV(DataSet<GeomType> * ds) : ds(ds) {}
    virtual ~InputLoaderCSV() = default;

    DataSet<GeomType> * ds;
};

and

template <typename GeomType>
struct DataSet
{
    template <typename LoaderType>
    static DataSet<GeomType> Create()
    {
        DataSet<GeomType> ds;
        ds.fileName = "something";
        ds.input = std::make_shared<LoaderType<GeomType>>(&ds);
        return std::move(ds);
    };

    DataSet(const DataSet & ds) = delete;

    DataSet(DataSet && ds)
    {
        this->fileName = std::move(ds.fileName);
        this->input = std::move(ds.input);
        this->input->ds = this;

        ds.input = nullptr;     
    }

    std::string fileName;
    std::shared_ptr<InputLoader<GeomType>> input;

   protected:   
        DataSet() : input(nullptr) {}
}

Now somewhere in code, I want to do

auto ds = DataSet<Line>::Create<InputCSV>();

where Line is some struct I have. However, this is not working and I got this error:

error C2672: 'DataSet<Line>::Create': no matching overloaded function found
error C3206: 'DataSet<Line>::Create': invalid template argument for 'LoaderType', missing template argument list on class template 'InputLoaderCSV'
note: see declaration of 'DataSet<Line>::Create' 
error cannot access protected member declared in class 'DataSet<Line>'
note: see declaration of 'DataSet<Line>::DataSet' note: see declaration of 'DataSet<Line>'

Is there any solution to have this kind of "syntax", or I have to write

auto ds = DataSet<Line>::Create<InputCSV<Line>>();

and change

ds.input = std::make_shared<LoaderType<GeomType>>(&ds);

to

ds.input = std::make_shared<LoaderType>(&ds);

In this example, I donw like "duplication" of in InputCSV, since there cannot be anything else.

Martin Perry
  • 9,232
  • 8
  • 46
  • 114

1 Answers1

3

What you are looking for is a template template parameter. Since InputCSV is a template type, you have to specify its template parameter. If you change Create to use a template template parameter instead then you can pass the template to Create and use it like you would any other template. To do that you need to use

template <template<typename> typename LoaderType>
// pre C++17 you have to use template <template<class> class LoaderType> instead
static DataSet<GeomType> Create()
{
    DataSet<GeomType> ds;
    ds.fileName = "something";
    ds.input = std::make_shared<LoaderType<GeomType>>(&ds);
    return std::move(ds);
}

and then you keep the use as

auto ds = DataSet<Line>::Create<InputCSV>();

and now LoaderType is a template type that takes a single template parameter that you can specify inside the function.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402