Jack
Jack

Reputation: 384

Variadic template arguments passed to template function

I have class which accepts one int template parameter, and one int parameter pack (neurons). One of the constructor's goals is to take each of the parameters in the pack and add an instance of a class to a vector. The class, however, takes its arguments as template parameters.

I have the following code:

template<int iCount, int... neurons>
class network {
private:
    std::vector<pl> layers;
public:
    network() : layers() {
        input_layer<iCount> inp;
        layers.push_back(inp);
        addLayer<iCount, neurons...>();
    }
    template<int prev, int nc, int... further>
    void addLayer() {
        layer<nc, prev> l;
        layers.push_back(l);
        addLayer<nc, further...>(); // error is here
    }
};

The recursive call, which is labeled with 'error is here', produces a compiler error: "Error 4 error C2783: 'void network<1,3,2,1>::addLayer(void)' : could not deduce template argument for 'nc'"

pl is the parent class of both input_layer and layer.

At the moment, I using network like so:

network<1, 3,2,1> n;

After invoking the constructor, I would expect that n.layers would contain four elements. The first being an input_layer, to which iCount was passed, and the remained being layers with the corresponding entry in neurons as its nc, and the previous layer's nc as its prev.

Upvotes: 2

Views: 165

Answers (2)

user2249683
user2249683

Reputation:

You might use tag dispatching to populate the vector:

#include <iostream>
#include <vector>

template<int... neurons>

class network {
public:
    std::vector<int> layers;

private:
    template <int N, int... Ns>
    struct tag {};

    template <int N, int... Ns>
    void addLayer(tag<N, Ns...>) {
        layers.push_back(N);
        addLayer(tag<Ns...>());
    }

    template <int N>
    void addLayer(tag<N>) {
        layers.push_back(N);
    }

public:
    network() {
        layers.reserve(sizeof ... (neurons));
        addLayer(tag<neurons...>());
    }
};

int main()
{
  network<1,2,3,4,5> n;
  for(int i : n.layers)
      std::cout << i;
  std::cout << '\n';
  return 0;
}

Note: Here the the count is determined by the number of integers passed to the template.

Upvotes: 0

Barry
Barry

Reputation: 302718

So first of all, you have object slicing, so you want:

std::vector<std::unique_ptr<pl>> layers;

Next, we can do this in one function without any recursion:

network() : layers() {
    layers.push_back(std::make_unique<input_layer<iCount>>());
    addLayers<iCount, neurons...>(std::make_index_sequence<sizeof...(neurons)>());
}

template <int... Pack, size_t... Is>
void addLayers(std::index_sequence<Is...> )  {
    static constexpr int array[] = {Pack...};

    int unused[] = {0,
        (layers.push_back(std::make_unique<layer<array[Is+1],array[Is]>>()), 0)...
    };
    (void)unused;
}

This solution inspired by T.C.'s answer here.

Upvotes: 2

Related Questions