11

मैंने हाल ही में एक वीडियो देखा जिसने मुझे अपना तंत्रिका नेटवर्क सिस्टम लिखने के लिए प्रेरित किया, और मैं नेटवर्क में नोड्स की मात्रा समायोज्य होना चाहता था।वैरिएड टेम्पलेटिंग पर निर्भर प्रकार वाले वर्ग

पहले मैंने इसे नोड्स की संख्याओं की एक सरणी को पार्स करके रनटाइम पर हासिल किया लेकिन मैं सोच रहा था कि मैं इसके बजाय संकलन समय पर ऐसा कर सकता हूं। यहां एक ऐसी चीज का उदाहरण दिया गया है जिसे मैं पूरा करने की उम्मीद कर रहा था।

template<int FirstNodes, int SecondNodes, int... OtherNodes> 
class Net 
{ 
    tuple<Eigen::Matrix<float, FirstNodes, SecondNodes>, ...> m_weights; 
    // More matricies with the values from the OtherNodes 
}; 

एक अधिक विस्तृत उदाहरण के रूप में, Net<784, 16, 16, 10> n; n.m_weight प्रकार

tuple<Eigen::Matrix<float, 784, 16>, 
    Eigen::Matrix<float, 16, 16>, 
    Eigen::Matrix<float, 16, 10>> 

मैं क्या सी ++ और constexpr जानते से होना चाहिए, यह संभव होना चाहिए।

मैं जोड़ने चाहिए कि मैं

template<int FirstNodes, int SecondNodes, int... OtherNodes> 
class Net 
{ 
public: 
    Net() 
    { 
     auto nodes = {FirstNodes, SecondNodes, OtherNodes...}; 

     auto i = nodes.begin(); 
     do 
     { 
      // Eigen::Matrix<float, Dynamic, Dynamic> 
      Eigen::MatrixXf m(*(i++), *i); 
     } while (i+1 != nodes.end()); 
    } 
}; 

ऐसा करने में सक्षम था लेकिन तब मैं सिर्फ गतिशील matricies फिर से उपयोग कर रहा हूँ और कहा कि नहीं है कि मैं क्या के लिए उम्मीद की गई थी।

कोई सलाह या काम करने वाले उदाहरणों की बहुत सराहना की जाएगी।

+0

वैसे, लाइन 'मीटर (* (i ++), * i)' का आह्वान C++ 14 तक अपरिभाषित व्यवहार, C++ 17 –

+0

* बेशर्म आत्म को बढ़ावा देने के * आपको पता चल सकता [में अनिर्दिष्ट यह रेपो] (https://github.com/liammcinroy/MetaTemplateNeuralNet) दिलचस्प है –

उत्तर

6

आप प्रकार परिवर्तन के कुछ प्रकार है कि N पूर्णांकों की एक सूची दी चाहते एक रिटर्न

template <int F, int S, int... Os> 
struct Net : NetBase<iList<0, F, S, Os...>, iList<F, S, Os..., 0>> 
{ }; 

निम्नलिखित है (पूर्णांक सूचियों के चरण जोड़ी से बाहर का पालन) N - 1 matrices के tuple। यहाँ एक सी ++ 17 समाधान है:

template <int A, int B, int... Is> 
auto make_matrix_tuple() 
{ 
    if constexpr(sizeof...(Is) == 0) 
    { 
     return std::tuple<Eigen::Matrix<float, A, B>>{}; 
    } 
    else 
    { 
     return std::tuple_cat(make_matrix_tuple<A, B>(), 
          make_matrix_tuple<B, Is...>()); 
    } 
} 

live example on wandbox


सी ++ 11 में, आप रिकर्सिवली इस प्रकार के परिवर्तन को लागू कर सकते हैं:

template <int... Is> 
struct matrix_tuple_helper; 

template <int A, int B, int... Rest> 
struct matrix_tuple_helper<A, B, Rest...> 
{ 
    using curr_matrix = Eigen::Matrix<float, A, B>; 
    using type = 
     decltype(
      std::tuple_cat(
       std::tuple<curr_matrix>{}, 
       typename matrix_tuple_helper<B, Rest...>::type{} 
      ) 
     ); 
}; 

template <int A, int B> 
struct matrix_tuple_helper<A, B> 
{ 
    using curr_matrix = Eigen::Matrix<float, A, B>; 
    using type = std::tuple<curr_matrix>; 
}; 

template <int... Is> 
using matrix_tuple = typename matrix_tuple_helper<Is...>::type; 

सी ++ 14 दृष्टिकोण:

struct matrix_tuple_maker 
{ 
    template <int A, int B, int C, int... Is> 
    static auto get() 
    { 
     return std::tuple_cat(get<A, B>(), get<B, C, Is...>()); 
    } 

    template <int A, int B> 
    static auto get() 
    { 
     return std::tuple<Eigen::Matrix<float, A, B>>{}; 
    } 
}; 

static_assert(std::is_same_v< 
    decltype(matrix_tuple_maker::get<784, 16, 16, 10>()), 
    std::tuple<Eigen::Matrix<float, 784, 16>, 
       Eigen::Matrix<float, 16, 16>, 
       Eigen::Matrix<float, 16, 10>> 
    >); 
1

मुझे ऐसा लगता है कि आप पूर्णांक के दो सूची की जरूरत है, के 1.

चरण से बाहर आप एक छोटी सी टेम्पलेट पूर्णांक कंटेनर निर्धारित करते

template <int...> 
struct iList 
{ }; 
(में सी ++ 14 यदि आप एक std::integer_sequence उपयोग कर सकते हैं)

आपको इस प्रकार आधार वर्ग परिभाषित कर सकते हैं (खेद: इस्तेमाल किया fooEigen::Matrix के बजाय)

template <typename, typename, typename = std::tuple<>> 
struct NetBase; 

// avoid the first couple 
template <int ... Is, int J0, int ... Js> 
struct NetBase<iList<0, Is...>, iList<J0, Js...>, std::tuple<>> 
    : NetBase<iList<Is...>, iList<Js...>, std::tuple<>> 
{ }; 

// intermediate case 
template <int I0, int ... Is, int J0, int ... Js, typename ... Ts> 
struct NetBase<iList<I0, Is...>, iList<J0, Js...>, std::tuple<Ts...>> 
    : NetBase<iList<Is...>, iList<Js...>, 
      std::tuple<Ts..., foo<float, I0, J0>>> 
{ }; 

// avoid the last couple and terminate 
template <int I0, typename ... Ts> 
struct NetBase<iList<I0>, iList<0>, std::tuple<Ts...>> 
{ using type = std::tuple<Ts...>; }; 

और Net बस बन एक पूर्ण संकलन उदाहरण

#include <tuple> 

template <int...> 
struct iList 
{ }; 

template <typename, int, int> 
struct foo 
{ }; 

template <typename, typename, typename = std::tuple<>> 
struct NetBase; 

// avoid the first couple 
template <int ... Is, int J0, int ... Js> 
struct NetBase<iList<0, Is...>, iList<J0, Js...>, std::tuple<>> 
    : NetBase<iList<Is...>, iList<Js...>, std::tuple<>> 
{ }; 

// intermediate case 
template <int I0, int ... Is, int J0, int ... Js, typename ... Ts> 
struct NetBase<iList<I0, Is...>, iList<J0, Js...>, std::tuple<Ts...>> 
    : NetBase<iList<Is...>, iList<Js...>, 
      std::tuple<Ts..., foo<float, I0, J0>>> 
{ }; 

// avoid the last couple and terminate 
template <int I0, typename ... Ts> 
struct NetBase<iList<I0>, iList<0>, std::tuple<Ts...>> 
{ using type = std::tuple<Ts...>; }; 

template <int F, int S, int... Os> 
struct Net : NetBase<iList<0, F, S, Os...>, iList<F, S, Os..., 0>> 
{ }; 

int main() 
{ 
    static_assert(std::is_same< 
     typename Net<784, 16, 16, 10>::type, 
     std::tuple<foo<float, 784, 16>, foo<float, 16, 16>, 
       foo<float, 16, 10>>>{}, "!"); 
} 
0

यहां एक और सी ++ 14 समाधान है। मैं इसे पोस्टिंग के लायक मानता हूं क्योंकि यह गैर-पुनरावर्ती और पठनीय है।

#include <tuple> 
#include <utility> 

template<class, int, int> struct Matrix {}; 

template<int... matsizes, std::size_t... matinds> 
constexpr auto make_net(
    std::integer_sequence<int, matsizes...>, 
    std::index_sequence<matinds...> 
) { 
    constexpr int sizes[] = {matsizes...}; 
    return std::tuple< Matrix<float, sizes[matinds], sizes[1+matinds]>... >{}; 
} 

template<int... matsizes> 
constexpr auto make_net(
    std::integer_sequence<int, matsizes...> sizes 
) { 
    static_assert(sizes.size() >= 2, ""); 
    constexpr auto number_of_mats = sizes.size() - 1; 
    return make_net(sizes, std::make_index_sequence<number_of_mats>{}); 
} 

int main() { 
    auto net = make_net(std::integer_sequence<int, 784, 16, 16, 10>{}); 
    using Net = decltype(net); 

    static_assert(
    std::is_same< 
     std::tuple< 
     Matrix<float, 784, 16>, 
     Matrix<float, 16, 16>, 
     Matrix<float, 16, 10> 
     >, 
     Net 
    >{}, "" 
); 

    return 0; 
} 
संबंधित मुद्दे