简体   繁体   中英

Recursive aggregate type configured using many template parameters using std::index_sequence

There is a class template:

template<std::size_t ID, std::size_t T1, std::size_t T2, std::size_t T3>
class Feature { /* Implementation goes here */ };

All the instantiations of Feature<...> are 'collected' here:

template<typename FEATURE, typename... OTHERS>
class Features<FEATURE, OTHERS...> : public Features<OTHERS...> {
public:
    /* Operations defined here */
private:
    FEATURE m_feature;
};

All the features are created as follows:

using FeatureConfig = Features<Feature<0, 1, 2, 3>, Feature<1, 4, 5, 6>>;
FeatureConfig m_features;

So far so good. My task is to get rid of those hard coded values in there 1..3, 4..6 etc. The way to do so is to have generated header file which contains the configuration for all the features. Something like:

template<std::size_t> struct Config;

template<>
struct Config<0> {
    static constexpr std::size_t t1 { 1 };
    static constexpr std::size_t t2 { 2 };
    static constexpr std::size_t t3 { 3 };
};

template<>
struct Config<1> {
    static constexpr std::size_t t1 { 4 };
    static constexpr std::size_t t2 { 5 };
    static constexpr std::size_t t3 { 6 };
};

Then I need to change type definition of FeatureConfig somehow to use the specializations of FeatureConfig based on an index (0, 1, ...). My unsuccessfull try is:

template<std::size_t... INDEX_SEQUENCE>
using FeatureConfig = Features<Feature<INDEX_SEQUENCE, Config<INDEX_SEQUENCE>::t1, Config<INDEX_SEQUENCE>::t2, Config<INDEX_SEQUENCE>::t3>...>;

FeatureConfig<std::make_index_sequence<2>> m_features;

It seems I am somehow mixing type and value...

Many thanks in advance to anyone willing to help me fix the incorrect code in my last listing up there.

Cheers Martin

If I understand correctly what do you want...

I propose the declaration (no definition required because is used only inside a decltype() ) of the following function

template <std::size_t ... Is>
auto getFeaturesType (std::index_sequence<Is...>)
   -> Features<Feature<Is, Config<Is>::t1, Config<Is>::t2, Config<Is>::t3>...>;

Now you can define FeatureConfig simply as follows

template <std::size_t N>
using FeatureConfig
   = decltype(getFeaturesType(std::make_index_sequence<N>{})); 

The following is a full compiling (simplified) example

#include <type_traits>
#include <utility>

template <std::size_t, std::size_t, std::size_t, std::size_t>
struct Feature { };

template <typename...>
struct Features
 { };

template <typename F, typename... Os>
struct Features<F, Os...> : public Features<Os...>
 { F m_feature; };

template <std::size_t N>
struct Config
 {
   static constexpr std::size_t t1 { N*3u };
   static constexpr std::size_t t2 { 1u + N*3u };
   static constexpr std::size_t t3 { 2u + N*3u };
 };

template <std::size_t ... Is>
auto getFeaturesType (std::index_sequence<Is...>)
   -> Features<Feature<Is, Config<Is>::t1, Config<Is>::t2, Config<Is>::t3>...>;

template <std::size_t N>
using FeatureConfig
   = decltype(getFeaturesType(std::make_index_sequence<N>{}));

int main () 
 {
   using T1 = FeatureConfig<2u>;
   using T2 = Features<Feature<0u, 0u, 1u, 2u>, Feature<1u, 3u, 4u, 5u>>;

   static_assert( std::is_same<T1, T2>::value, "!" );
 }

If I understand correctly how do you use Config (if t1 is ever N*3u , if if t2 is ever 1u+N*3u and if t3 is ever 2u+N*3u ), you can avoid Config at all and write getFeaturesType as follows

template <std::size_t ... Is>
auto getFeaturesType (std::index_sequence<Is...>)
   -> Features<Feature<Is, Is*3u, Is*3u+1u, Is*3u+2u>...>;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM