شخصيتك c++ 11 البرمجة فارياديك، كيفية تحديد برج من ناقلات



الابراج بتاريخ الميلاد والاسم (2)

كيف يمكن (إن أمكن) استخدام البرمجة C ++ 11 فارياديك لتحديد سلسلة من vector في هيئة الدالة، (أو بعبارة أخرى، تسلسل صفائف N ديمنزيونال مع انخفاض N 's حتى 0)، مثل المتغيرات أدناه؟

vector<vector<vector<int>>> v<3>;
vector<vector<int>> v<2>;
vector<int> v<1>;
int v<0>;

ما تخيلت هو شيء مثل:

#include <iostream>
#include <vector>
using namespace std;

template<int ...> struct seq {};
template<int N, int ...S> struct gens : gens<N-1, N-1, S...> {};
template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; };

template<int ...S>
void f(seq<S...>) {
  //how do I write definitions of v<N> here?
  vector<vector<...(N layers)<vector<int> ...> v<N>;     //??how-to, not valid c++
  vector<vector<...(N -1 layers)<vector<int> ...> v<N-1>;//??how-to, not valid c++
  //...
  vector<int> v<1>;  //??how-to, not valid c++
  int v<0>;          //??how-to, not valid c++

  //...
}

int main() {
  f(typename gens<3>);
  return 0;
}

أيضا، هل سيكون هذا أسهل في c ++ 14؟

شكر،

--تصحيح--

فقط لتوضيح، ما أعنيه ب "برج النواقل" هو أفضل وصفها من قبل N-توبل (V_1، V_2، ...، v_N)، حيث N هو معلمة قالب متكامل. v_1 هو متجه، v_2 من ناقلات>، وهلم جرا.

--EDIT2--

حتى الآن، وقد حلت إجابات كوانتديف و R بنجاح مشكلة تحديد N- توبل لأي N ثابتة، مثل 3، ولكن لا يمكن أن تولد لابل غير محدد N بالإضافة إلى وظيفة في الإجابات، ولست بحاجة إلى وظيفة التي يمكن استخدامها مثل gen_tower<N> أن يعود tuple(v1,v2,...,vN) .

النظر في مثال استخدام البرمجة فارياديك لحساب فاكتوريالز. أنا بحاجة إلى وظيفة لحساب مضروب factorial<N>() لأي N ، بالإضافة إلى القدرة على كتابة أي تعبير محدد <1*2*3> يدويا. (وهذا هو السبب الذي سألته عن البرمجة فاريديك وما إذا كان c++14 سوف تجعل من الأسهل.)

PS

بحتة من المصالح الشخصية، أريد هذا التسلسل على أمل تنفيذ وظيفة عامة التي يمكن قراءة صفيف N- الأبعاد من الملف. أنا لا أعرف بالضبط كيف حتى الآن، ولكن أعتقد في الخطوة الأولى، ينبغي أن أكون قادرا على تحديد مجموعة N الأبعاد النهائي، ومصفوفات k المتوسطة ل k من N-1 إلى 1 . أستطيع أن أقرأ المصفوفات ثنائية الأبعاد، و 3-الأبعاد. ولكن سيكون من الجميل أن تكون قادرة على قراءة صفائف من أي أبعاد.

https://ffff65535.com


لن أذهب إلى الكثير من التفاصيل في إنشاء برج واحد لأنه هو موضح من قبل إجابات أخرى هنا. هنا هو نسختي من gen_tower<T, I> الذي يولد برج من ناقلات العمق I .

على سبيل المثال، gen_tower_t<int, 2> هي std::vector<std::vector<T>> .

// Useful for defining meta-functions compactly.
template <typename T>
struct identity { using type = T; };

gen_tower <T، I>

// Forward declaration.
template <typename T, std::size_t I>
struct gen_tower;

// Convenience type alias.
template <typename T, std::size_t I>
using gen_tower_t = typename gen_tower<T, I>::type;

// Base case.
template <typename T>
struct gen_tower<T, 0> : identity<T> {};

// Wrap std::vector around tower of depth I - 1.
template <typename T, std::size_t I>
struct gen_tower : identity<std::vector<gen_tower_t<T, I - 1>>> {};

gen_towers <T، N>

الآن يمكننا استخدام std::index_sequence لتحديد N الأبراج.

// Generate a tuple of towers by mapping index_sequence over gen_tower.
template <typename T, std::size_t... Is>
std::tuple<gen_tower_t<T, Is>...> gen_towers_impl(std::index_sequence<Is...>);

// Make an index_sequence for N and use gen_towers_impl.
template <typename T, std::size_t N>
struct gen_towers
    : identity<
          decltype(gen_towers_impl<T>(std::make_index_sequence<N>()))> {};

// Convenience type aliases
template <typename T, std::size_t N>
using gen_towers_t = typename gen_towers<T, N>::type;

أمثلة

static_assert(std::is_same<gen_tower_t<int, 0>, int>::value, "");

static_assert(std::is_same<
                  gen_tower_t<int, 2>,
                  std::vector<std::vector<int>>>::value, "");

static_assert(std::is_same<
                  gen_towers_t<int, 2>,
                  std::tuple<int, std::vector<int>>>::value, "");

static_assert(std::is_same<
                  gen_towers_t<int, 3>,
                  std::tuple<int,
                             std::vector<int>,
                             std::vector<std::vector<int>>>>::value, "");

int main() {}

ليست هناك حاجة ل فارياديكس، تيبيديف العودية كافية لتوليد تلك الأنواع في وقت تجميع.

كيف يتم تنفيذه؟

1) تقديم قالب مع وسيطتين: نوع العناصر المتجهة ( T )، والبعد المطلوب للبنية ( size_t N ). تعلن type تيبيديف: وسوف يستند على إعلان type للقالب مثبت مع عمق N-1 ، وبالتالي التكرار.

template<typename T, size_t N>
struct VectorGenerator
{
    typedef std::vector< typename VectorGenerator<T, N-1>::type > type;
};

2) توفير حالة إنهاء لإنهاء العودية، وهنا تخصص قالب لدينا مع البعد 0، معلنا نوع المعتاد std::vector<T> .

template<typename T>
struct VectorGenerator<T, 0>
{
    typedef std::vector<T> type;
};

كيفية استخدامها ؟

يمكننا الآن أن نعلن متجه v من نوع VectorGenerator<T, N>::type :

VectorGenerator<double, 4>::type v; // v as a depth of 4 and handle double

ولكنها ليست مقروءة جدا أو مريحة، ومطولة جميلة. دعونا نقدم أسماء جديدة لأنواعنا.

هذه هي الحالة المثالية للتسمية القالب ، مع (C ++ 11) using الكلمة الرئيسية للتسمية. لدينا 2 طرق مختلفة من التعرج:

1) إعلان اسم مستعار لبعد ونوع معين، وهنا نسميها V3 ل N=3 و T=double :

using V3 = VectorGenerator<double, 3>::type;  // Alias

V3 v;                                         // Use the alias

أو،

2) إعلان اسم مستعار للنموذج معين، وترك البعد كمعلمة قالب:

template <size_t N> 
using V = typename VectorGenerator<double, N>::type;  // Alias

V<3> v;                                              // Use the Alias

نموذج الرمز النهائي:

template<typename T, size_t N>
struct VectorGenerator
{
    typedef std::vector< typename VectorGenerator<T, N-1>::type > type;
};

template<typename T>
struct VectorGenerator<T, 0>
{
    typedef std::vector<T> type;
};

// Alias for V3, V2 ... usage
using V3 = VectorGenerator<double, 3>::type;
using V2 = VectorGenerator<double, 2>::type;

// Alias for V <k> usage
template <size_t N> 
using V = typename VectorGenerator<double, N>::type;

int main() {

    V<3> v3;
    V<2> v2;
    v3.push_back(v2);
    return 0;
}

ملاحظات :

  • النظر في مكتبة مصفوفة متعددة الأبعاد .
  • لست متأكدا من هدفك النهائي، ولكن هذا قد يكون مبالغا فيه.
  • أما بالنسبة للتحرير الثاني الخاص بك، tuple عن tuple مع ناقلات متعددة من أبعاد مختلفة من السهل الآن:

مثال:

auto tower = std::tuple<V<1>, V<2>, V<3>>(v1, v2, v3);

لجيل الجيل العام من "أبراج" متعددة، أعطىmpark حل C ++ 14 العمل ، وأنا على التكيف هنا إلى بلدي رمز عينة:

template <typename T>
struct identity { using type = T; };

// Generate a tuple of towers by mapping index_sequence over gen_tower.
template <typename T, std::size_t... Is>
std::tuple<VectorGenerator<T, Is>...> gen_towers_impl(std::integer_sequence<Is...>);

// Make an index_sequence for N and use gen_towers_impl.
template <typename T, std::size_t N>
struct gen_towers
    : identity<decltype(gen_towers_impl<T>(std::make_index_sequence<N>()))> {};

// Convenience type aliases
template <typename T, std::size_t N>
using gen_towers_t = typename gen_towers<T, N>::type;

ستحتاج -std=c++1y (وتشمل <utility> و <tuple> رؤوس)

اطلع على مثال عملي هنا .





c++14