Превращение # ifdef в шаблонную метапрограмму в переполнении стека

У меня есть следующий код внутри класса C ++:

class Features
{
#define Feature_Size_A 12345
#define Feature_Size_B 45678
#define Feature_Size_C 78901
//#define Feature_Size_D 14725

const int Feature_Sum = 0
#ifdef Feature_Size_A
+ Feature_Size_A
#endif
#ifdef Feature_Size_B
+ Feature_Size_B
#endif
#ifdef Feature_Size_C
+ Feature_Size_C
#endif
#ifdef Feature_Size_D
+ Feature_Size_D
#endif
;

#ifdef Feature_Size_A
static float Feature_A[Feature_Size_A];
#endif
#ifdef Feature_Size_B
static float Feature_B[Feature_Size_B];
#endif
#ifdef Feature_Size_C
static float Feature_C[Feature_Size_C];
#endif
#ifdef Feature_Size_D
static float Feature_D[Feature_Size_D];
#endif
};

Раньше я комментировал функции, такие как строка 4, для компиляции и запуска различных тестов. Но теперь я хотел бы иметь класс в качестве шаблона, чтобы я мог создавать экземпляры нескольких версий с различными функциями, включенными или выключенными в одной и той же программе.

Я думаю о чем-то вроде этого:

template <bool Feature_A, bool Feature_B, bool Feature_C, bool Feature_D>
class Features
{
...
};

Features<true, true, true, false> f;

Я пробовал с boost :: mpl: vector’s, но я борюсь изо всех сил.

Кстати: это не полный код. Оригинальный код имеет 25 функций.

Я благодарен за каждую идею, не связанную с макросами 🙂

5

Решение

Списки типов могут быть использованы для решения этой проблемы.

template<unsigned num, unsigned size, typename T>
class Feature : public T
{
public:
static float feature[size];
static const unsigned int feature_sum = size + T::feature_sum;
};
template<unsigned num, unsigned size, typename T>
float Feature<num, size, T>::feature[size];
class Tail {
public:
static const unsigned feature_sum = 0;
};

template<unsigned num, unsigned size, typename T>
float* get_feature_arr(Feature<num, size, T>& ref)
{
return ref.feature;
}

int main() {
Feature<1, 12345, Feature<2, 45678, Feature<4, 78901, Tail>>> TripleFeatures;
auto first = get_feature_arr<1>(TripleFeatures);
auto third = get_feature_arr<4>(TripleFeatures);
auto size = TripleFeatures.feature_sum;
}

Это также может быть использовано для доступа к любой функции, независимо от того, какие другие функции есть или нет в списке.

Редактировать: я перечислил некоторые детали, например, не определяя массив и пытаясь использовать «3features» в качестве идентификатора. Ле исправлено. Код компилирует GCC 4.7.1.

3

Другие решения

Почему бы не использовать статически размещенные массивы?

#include <stdio.h>

template <bool Feature_A, bool Feature_B, bool Feature_C, bool Feature_D>
class Features
{
static const int Feature_Size_A = 12345;
static const int Feature_Size_B = 45678;
static const int Feature_Size_C = 78901;
static const int Feature_Size_D = 14725;
static const int Feature_Sum = 0
+ Feature_A ? Feature_Size_A : 0
+ Feature_B ? Feature_Size_B : 0
+ Feature_C ? Feature_Size_C : 0
+ Feature_D ? Feature_Size_D : 0
;

public:
static float Feature_Vector_A[Feature_A ? Feature_Size_A : 0];
static float Feature_Vector_B[Feature_B ? Feature_Size_B : 0];
static float Feature_Vector_C[Feature_C ? Feature_Size_C : 0];
static float Feature_Vector_D[Feature_D ? Feature_Size_D : 0];
};

Features<true, true, true, true> f1;
Features<true, true, true, false> f2;

int main()
{
printf("%d %d\n", sizeof(f1.Feature_Vector_D), sizeof(f2.Feature_Vector_D));
}

Выход:

58900 0
1

Не совсем точно, какие именно функции будут, но вот решение, которое позволяет условно включать функции-члены, а также данные-члены:

namespace mpl = boost::mpl;

// Define your features
struct FeatureA
{
static const int size = 12345;
static float Feature_A[size];

static void methodA() {}
};
float FeatureA::Feature_A[12345];

struct FeatureB
{
static const int size = 45678;
static char Feature_B[size]; // possibly different types of data (?)

static void methodB() {}
};
float FeatureB::Feature_B[45678];

struct FeatureC
{
static const int size = 78901;
static int Feature_C[size];

static void methodC() {}
};
float FeatureC::Feature_C[78901];// Helper metafunction
template <typename T>
struct get_size
: mpl::int_<T::size>
{};template <typename FeaturesSeq>
struct Features_impl
: mpl::inherit_linearly<
FeaturesSeq,
mpl::inherit<mpl::_, mpl::_>
>::type
{
static const int Feature_Sum =
mpl::accumulate<
FeaturesSeq,
mpl::int_<0>,
mpl::plus<
mpl::_1,
get_size<mpl::_2>
>
>::type::value;
};

template <typename... F>
using Features = Features_impl<mpl::vector<F...>>;#include <iostream>

int main()
{
typedef Features<FeatureA, FeatureC> F;

std::cout << F::Feature_Sum << '\n';

F::Feature_A[0] = 12.0f;
F::methodA();

F::methodC();
}

Если все ваши функции на самом деле просто плавающие массивы, как в вашем примере, вы можете использовать универсальный Feature учебный класс

template <int Size>
struct Feature
{
static float data[Size];
};
template <int Size>
float Feature::data[Size];

И хранить специализации этого класса в векторах mpl:

typedef mpl::vector<Feature<1234>, Feature<5678>> Features;

mpl::at_c<Features, 0>::type::data[0] = 12.0f;
// could be encapsulated into a helper function

Без дополнительной информации о назначении этих так называемых функций трудно дать более полный ответ.

1