Возможно ли иметь шаблонный шаблон "generi c" в C ++, который может быть либо нетиповым параметром шаблона, либо типом? - PullRequest
2 голосов
/ 01 февраля 2020

В C ++ в качестве параметра шаблона можно использовать тип, например:

template <typename T>
void MyFn();

В некоторых случаях в качестве параметра шаблона также можно использовать не тип, например:

template <int64_t T>
void MyFn2();

Мой вопрос: возможно ли иметь шаблонный шаблон «generi c», который может быть и тем, и другим? Например:

template <TypenameOrint64_t T>
void MyFn3();

, так что MyFn3<42> и MyFn3<double> будут приемлемы.

Пример того, как я мог бы использовать это:

template <typename ValType, ValType Head, ValType ...Tail>
struct ListS{

  template <typename OutType, template <ValType ArgType> class Fn>
  using MapHead = ListS<OutType, Fn<Head>::val, Tail...>;
};

template<int64_t N>
struct SquareS{
  static constexpr const int64_t val = N * N;
};

using Sqrd = ListS<int64_t, 3, 4>::MapHead<int64_t, SquareS>;

static_assert(std::is_same<Sqrd, ListS<int64_t, 9, 4>>::value, "Values don't match");

выше приведен очень грубый набросок списка значений во время компиляции вместе с единственной «функцией» времени компиляции. Можно ли сделать что-то подобное, поддерживающее списки типов, а не просто списки значений, не совместимых с параметрами типа шаблона, без дублирования всего кода?

Ответы [ 2 ]

3 голосов
/ 01 февраля 2020

Возможно ли иметь «общий» шаблонный параметр в C ++, который может быть либо нетиповым параметром шаблона, либо типом?

Краткий ответ: нет.

Длинный ответ.

Нет. Лучшее, что я могу себе представить, чтобы смешивать типы и значения, это переносить значения в типах, используя, например, std::integral_constant.

Итак, ваш желаемый код может быть написан (C ++ 17) почти следующим образом

#include <utility>

template <typename ...>
struct ListS;

template <typename ValType, ValType Head, ValType ...Tail>
struct ListS<std::integral_constant<ValType, Head>,
             std::integral_constant<ValType, Tail>...>
 {
   template <template <auto> class Fn, typename OutType = ValType>
   using MapHead = ListS<std::integral_constant<OutType, Fn<Head>::value>,
                         std::integral_constant<OutType, Tail>...>;
 };

template <auto N>
struct SquareS : public std::integral_constant<decltype(N), N*N>
 { };

int main ()
 {   
   using T1 = ListS<std::integral_constant<long long, 3ll>,
                    std::integral_constant<long long, 4ll>>;
   using T2 = T1::MapHead<SquareS>;
   using T3 = ListS<std::integral_constant<long long, 9ll>,
                    std::integral_constant<long long, 4ll>>;

   static_assert( std::is_same_v<T2, T3> );
 } 

До C ++ 17 вы не можете использовать auto для типа значений шаблона, поэтому вы должны внести некоторые простые исправления.

2 голосов
/ 01 февраля 2020

Вы можете использовать перегрузку функций и вычет типа auto, которые идут с C++17 для достижения sh чего-то похожего.

template<typename myType>
auto myFn3(myType value){
    return value;
}

template<auto value> //takes any non-type parameter
auto myFn3(){
    return value;
}

int main(){
     auto test1_normal = myFn3(3);
     auto test1_cast = myFn3<double>(3); //able to perform a cast
     auto test1_auto = myFn3<3>();
    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...