2015-11-28 5 views
2

У меня есть std::array, который заполнен всеми типами перечисления. Я бы хотел реализовать мои кортежи на основе .Как автоматизировать создание наборов шаблонных классов на основе элементов массива?

class CompBase 
{ 
public: 
    enum CompType{ 
     INPUT, 
     GRAPHICS 
     // (+ 5-10 additional types) 
    }; 

    static const std::array<CompType, 2> compTypeArr; 
}; 

const std::array<CompBase::CompType, 2> CompBase::compTypeArr = 
{ 
    CompBase::INPUT, 
    CompBase::GRAPHICS 
}; 

template<CompBase::CompType compType_e> 
class CompHolder {}; // owns one component 

template<CompBase::CompType compType_e> 
class CompContainer {}; // references N components 

class CompInterface 
{ 
    // ... 
private: 
    std::tuple // I want to automate this, 
    < 
     CompHolder<CompBase::INPUT>, 
     CompHolder<CompBase::GRAPHICS> 
    > compHolders; 
}; 

class CompHandler 
{ 
    // ... 
private: 
    std::tuple // and this process, based on the predefined array 
    < 
     CompCont<CompBase::INPUT>, 
     CompCont<CompBase::GRAPHICS> 
    > compContainers; 
}; 

В моем понимании std::make_tuple даже не constexpr перед тем c++14ref , так что я не уверен, если это вообще возможно, так как я был бы нужен метод c++11. Наличие массива я считаю вроде обязательным, поскольку только перечисление не предоставляет необходимых функций для чего-то вроде этого.

+0

как насчет того, чтобы вы перечислили список типов? то было бы намного проще использовать позже. IMHO, перечислив список «типов», довольно беден, для этого существуют вариативные шаблоны. – OznOg

+0

Это может быть плохо, но я получаю довольно приятные функциональные возможности, и это проще реализовать; хотя да, у меня есть несколько проблем. Я использовал вариационные шаблоны раньше, и я на самом деле не думаю, что они сделают вещи чище, чем это, или как расширяемые (если это сработает, с другой стороны, я очень открыт для него, конечно). – MatrixAndrew

+0

Поскольку вам не кажется, что вам нужно дважды писать список счетчиков (это третья копия, которую вы хотите автоматизировать здесь), тогда вы можете сохранить «enum» и заменить «array» на экземпляр вариационного шаблона , из которого вы можете получить требуемую автоматизацию. Это похоже на решение? – bogdan

ответ

1

Вот решение, которое работает на C++ 11. Как обсуждалось в комментариях, использование std::array будет работать в C++ 14, где его конструкторы доступа были сделаны constexpr.

#include <tuple> 
#include <type_traits> 
#include <iostream> 

class CompBase 
{ 
public: 
    enum CompType { 
     INPUT, 
     GRAPHICS 
     // (+ 5-10 additional types) 
    }; 
}; 

template<CompBase::CompType...> struct CTLHelper; 
using CompTypeList = CTLHelper< 
    CompBase::INPUT, 
    CompBase::GRAPHICS 
>; 

template<template<CompBase::CompType> class, class> struct CompTupleMaker; 
template<template<CompBase::CompType> class H, CompBase::CompType... Es> 
struct CompTupleMaker<H, CTLHelper<Es...>> 
{ 
    using type = std::tuple<H<Es>...>; 
}; 

template<CompBase::CompType compType_e> 
class CompHolder {}; // owns one component 

template<CompBase::CompType compType_e> 
class CompContainer {}; // references N components 

using CompHolderTuple = CompTupleMaker<CompHolder, CompTypeList>::type; 
using CompContainerTuple = CompTupleMaker<CompContainer, CompTypeList>::type; 

class CompInterface 
{ 
    // ... 
private: 
    CompHolderTuple compHolders; 
}; 

class CompHandler 
{ 
    // ... 
private: 
    CompContainerTuple compContainers; 
}; 


int main() 
{ 
    // just a quick check 
    std::cout << std::is_same<CompHolderTuple, std::tuple<CompHolder<CompBase::INPUT>, CompHolder<CompBase::GRAPHICS>>>::value << '\n'; 
} 

Если вам действительно нужны эти счётчики в массиве в C++ 11, вы можете использовать встроенный в массив, объявленный constexpr - вы можете ссылаться на его элементы в константных выражениях. Я бы сказал, что это имеет смысл только в том случае, если вам нужен массив для чего-то другого; если все, что вам нужно, является держателем списка перечислителей, в этом случае вариационное решение проще. Для решения массива вам понадобится нечто похожее на C++ 14's std::index_sequence, чтобы развернуть массив.

+0

Замечательно, спасибо! – MatrixAndrew

+0

Могу ли я спросить, вы объявили 'CompTupleMaker' со вторым аргументом шаблона типа для вызова предупреждения компилятора, если передан параметр' non-CompType' или есть другие причины для этого? – MatrixAndrew

+1

@AromaticCodeProducer Второй параметр 'CompTupleMaker' предназначен для типа, который содержит список счетчиков CompType (в аргументах шаблона, используемых для его создания). Нам нужен этот список, который передается как пакет параметров, чтобы что-то расширялось при создании «tuple» специализации. Частичная специализация «CompTupleMaker» решает эту проблему. Это также гарантирует, что мы получим ошибку компилятора, если что-то еще, чем специализация «CTLHelper», передается, так как это попытается создать экземпляр первичного шаблона, который не определен. – bogdan