Расширение типа пакета параметров C ++ - PullRequest
1 голос
/ 08 апреля 2020

Я играл с пакетами параметров в c ++, и вот чего я хотел бы достичь:

У меня есть 3 структуры:

struct Base {
    Base(int x) : x(41) {}
    int x;
};

struct A : Base {
    A() : Base(41) {}
};

struct B : Base {
    B() : Base(42) {}
};

И я хотел бы создать обобщение c функция, которая возвращает кортеж с экземплярами указанных типов, т.е.

magicFunction<A,B,A,B,A> == std::tuple{A(), B(), A(), B(), A()} 
magicFunction<A,B,A> == std::tuple{A(), B(), A()} 

Я пытался использовать специализацию шаблонов для расширения типов, но, к сожалению, не смог этого сделать (я понимаю, почему это не так скомпилировать, просто не знаю как это исправить :))


template<typename isEmpty, typename ...T>
struct ExpanderImpl {

};

template<typename Head, typename ... Rest>
struct ExpanderImpl<std::false_type, Head, Rest...> {
    static std::tuple<Head, Rest...> getValues() {
        if(sizeof...(Rest) > 0) {
            return std::tuple_cat(std::tuple{Head()}, ExpanderImpl<std::false_type, Rest...>::getValues());
        } else {
            return std::tuple_cat(std::tuple{Head()}, ExpanderImpl<std::true_type, Rest...>::getValues());
        }
    }
};

template<typename ...Empty>
struct ExpanderImpl<std::true_type, Empty...> {
    static std::tuple<Empty...> getValues() {
        return {};
    }
};

template<typename ...T>
struct Expander {
    static std::tuple<T...> getValues() {
        if(sizeof...(T) > 0) {
            return ExpanderImpl<std::false_type, T...>::getValues();
        } else {
            return ExpanderImpl<std::true_type, T...>::getValues();
        }
    }

};

Есть предложения как это исправить? Кроме того, есть ли лучший способ достичь того, что я хочу?

Полный код можно найти здесь здесь . Спасибо за помощь.

Ответы [ 3 ]

1 голос
/ 08 апреля 2020

Вы, похоже, ищете

template <typename... T>
using magicFunction = std::tuple<T...>;

int main() {
    magicFunction<A,B,A>();

    // If no default constructors supplied.
    magicFunction<Base,Base,Base>(41, 42, 41); 
}
1 голос
/ 08 апреля 2020

То, что вы ищете, это

template <typename... T> std::tuple<T...> magicFunction() 
{
    return {};
}

, и вы бы назвали его как

magicFunction<A,B,A,B,A>();

И он вернет std::tuple<A,B,A,B,A>. Это работает так: return {}; говорит, что возвращает возвращаемое значение инициализированного значения (T() / T{}), а возвращаемое значение - std::tuple<T...>, которое является кортежем всех параметров шаблона

0 голосов
/ 08 апреля 2020
  • В то время как существуют более простые способы создания кортежа, ваш путь терпит неудачу, так как обе ветви должны быть созданы с помощью обычного if.

    if constexpr (C ++ 17) решает, что Демонстрация .

    Обратите внимание, что std::tuple{Head()} также является конструкцией C ++ 17.

    C ++ 11 будет std::tuple<Head>{} или std::make_tuple(Head()).

  • Чтобы сохранить реализацию в C ++ 11, можно избавиться от этой среды выполнения if и использовать std::conditional для использования std::true_type / std::false_type

    template<typename Head, typename ... Rest>
    struct ExpanderImpl<std::false_type, Head, Rest...> {
        static std::tuple<Head, Rest...> getValues() {
            return std::tuple_cat(
                std::make_tuple(Head()),
                ExpanderImpl<typename std::conditional<(sizeof...(Rest) == 0),
                                                       std::true_type,
                                                       std::false_type>::type,
                             Rest...>::getValues());
        }
    };
    
    template<typename ...T>
    struct Expander {
        static std::tuple<T...> getValues() {
            return ExpanderImpl<typename std::conditional<(sizeof...(T) == 0),
                                                          std::true_type,
                                                          std::false_type>::type,
                                T...>::getValues();
        }
    };
    

    Демо .

  • И вы можете избавиться от is_empty с различной специализацией:

    template<typename ...Ts> struct Expander;
    
    // Non empty case
    template<typename Head, typename ... Rest>
    struct Expander<Head, Rest...> {
        static std::tuple<Head, Rest...> getValues() {
            return std::tuple_cat(
                std::make_tuple(Head()),
                Expander<Rest...>::getValues());
        }
    };
    
    // Empty case
    template<>
    struct Expander<> {
        static std::tuple<> getValues() { return {}; }
    };
    

    Демо .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...