Создать складной пакет параметров шаблона - PullRequest
0 голосов
/ 19 декабря 2018

Вопрос

Можно ли создать складной (※ выражение сгиба ) шаблон пакет параметров ?

Пример

Рассмотрим следующий пример (функция, которая принимает два аргумента типа int ( decayed )).

template<
    typename L,
    typename R,
    typename = std::enable_if_t<
            std::is_same_v<int, std::decay_t<L>>
        &&  std::is_same_v<int, std::decay_t<R>>
    >
>
int F(L Left, R Right){
    return 0x70D0;
}

Можно ли создать пакет параметров шаблона, который можно свернуть, чтобы избежать записиодин и тот же фрагмент кода несколько раз ( то есть std::is_same_v)?

То, что представлено ниже как std::pack, может упростить использование SFINAE?

typename = std::enable_if_t<(... && std::is_same_v<int, std::decay_t<std::pack<L, R>>>)>

Что я 'я пробовал

Я пытался решить проблему, используя T pack и совмещая псевдонимы L и R.Но по некоторым причинам следующий код компилируется и запускается без ошибки (второй аргумент второго F вызова функции, затухший, не равен int) в MSVC 15.9.4 + 28307.222:

template<
    typename... T,
    typename L = std::tuple_element_t<0, std::tuple<T...>>,
    typename R = std::tuple_element_t<1, std::tuple<T...>>,
    typename = std::enable_if_t<(... && std::is_same_v<int, std::decay_t<T>>)>
>
int F(L Left, R Right){
    return 0x70D0;
}

int main(){
    F(3, 5);   // OK
    F(3, "5"); // OK, but should not compile
}

PS Кроме того, я что-то упустил в приведенном выше коде, чтобы заставить SFINAE работать должным образом (функции фильтра только с int, int (затухшими) аргументами)?

Ответы [ 3 ]

0 голосов
/ 19 декабря 2018

Слишком поздно для воспроизведения?

Можно ли создать пакет параметров шаблона, который можно сложить, чтобы избежать многократной записи одного и того же фрагмента кода?

Ненасколько я знаю, в самом F().

Но вы можете упаковать типы, например, в список вызываемой функции.

Я имею в виду ... если вы объявить определить (только объявить: нет необходимости определять это, потому что используется только в decltype()) следующая функция [Редактировать: как предложил Барри (спасибо), определяющий функциюупростить использование]

template <typename T, typename ... Ts>
constexpr auto isSameList ()
   -> std::bool_constant<(... && std::is_same_v<T, std::decay_t<Ts>>)>
 { return {}; } 

, где вы можете использовать свертывание шаблонов, вы можете SFINAE включить / отключить F() следующим образом

template <typename L, typename R,
          std::enable_if_t<isSameList<int, L, R>(), bool> = true>
int F(L Left, R Right)
 { return 0x70D0; }

Ниже приведен полный пример компиляции

#include <type_traits>

template <typename T, typename ... Ts>
constexpr auto isSameList ()
   -> std::bool_constant<(... && std::is_same_v<T, std::decay_t<Ts>>)>
 { return {}; } 

template <typename L, typename R,
          std::enable_if_t<isSameList<int, L, R>(), bool> = true>
int F(L Left, R Right)
 { return 0x70D0; }

int main ()
 {
    F(3, 5);   // compile
    //F(3, "5"); // compilation error
 }
0 голосов
/ 21 декабря 2018

У вас почти было это:

template <typename L,typename R,
  typename = std::enable_if_t<std::is_same_v<std::tuple<int,L,R>,std::tuple<L,R,int>>>>
int F(L Left, R Right){
    return 0x70D0;
}

int main(){
    F(3, 5);   // OK
    F(3, "5"); // Does not compile
    F("5", 3); // Does not compile
}

или вариационная версия:

template <typename... T,
  typename = std::enable_if_t<std::is_same_v<std::tuple<int,T...>,std::tuple<T...,int>>>>
int F(T... args){
    return 0x70D0;
}

int main(){
    F(3, 5);   // OK
    F(3, "5"); // Does not compile
    F("5", 3); // Does not compile
}
0 голосов
/ 19 декабря 2018

Можно ли создать пакет параметров шаблона, который можно свернуть, чтобы избежать многократной записи одного и того же фрагмента кода?

На месте?Не в C ++ 17.Вам нужно будет обернуть ваши типы в какой-то template <typename...> struct typelist;, а затем развернуть их где-нибудь еще.Это требует одного уровня косвенности.

Насколько я знаю, нет никакого способа написать что-то вроде std::pack.


Я пытался решить проблему, используяT pack и псевдонимы одиночных L и R. [...]

В вашем коде T... всегда будет пустым, так как он ничего не выводит.Значения параметров шаблона L и R по умолчанию игнорируются, так как они выводятся вызовом функции.

Вам нужно что-то вроде:

template<
    typename... T,
    typename = std::enable_if_t<(... && std::is_same_v<int, T>)>
>
int F(T...){
    return 0x70D0;
}

InC ++ 20, вы должны иметь возможность использовать лямбду следующим образом:

template<
    typename L,
    typename R,
    typename = std::enable_if_t<[]<typename... Ts>(){
        return (... && std::is_same_v<int, Ts>)
    }.operator()<L, R>()>
>
int F(L Left, R Right){
    return 0x70D0;
}
...