2

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.

manlio
  • 18,345
  • 14
  • 76
  • 126
Jack
  • 396
  • 2
  • 18

2 Answers2

2

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.

Community
  • 1
  • 1
Barry
  • 286,269
  • 29
  • 621
  • 977
  • I'm having trouble finding an include file for `make_index_sequence` in Visual Studio. – Jack Jun 11 '15 at 17:27
  • @Jack It's in [``](http://en.cppreference.com/w/cpp/utility/integer_sequence). If VC doesn't have it, then there are various implementations posted around here. For example, [this question](http://stackoverflow.com/q/17424477/2069064) – Barry Jun 11 '15 at 17:29
  • Visual Studio does not support `constexpr` as you used it. What's an alternative? – Jack Jun 11 '15 at 17:42
  • 1
    @Jack A quick hack is `template using at_t = std::tuple_element_t...>>;`, then use `at_t::value` instead of `array[Is+1]`. – T.C. Jun 11 '15 at 18:45
0

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.