Можно ли создать складной (※ сложить выражение) шаблон пакет параметров?
Рассмотрим следующий пример (функция, которая принимает два аргумента типа int (разложившийся)).
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 и псевдонимы одиночных 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 (распавшимися))?
@ Ханс, ТАК работает не так. Если вопрос по теме, то он принадлежит сообществу SO. Мы не удаляем таким образом хороший контент.
@TobySpeight Я не был уверен, откатывать ли удаление вопроса OP или VTC - я откатываюсь в следующий раз





Is it possible to create template parameter pack that can be folded to avoid writing same fragment of code multiple times?
На месте? Не в C++ 17. Вам нужно будет обернуть ваши типы в какой-то template <typename...> struct typelist;, а затем развернуть их где-нибудь еще. Это требует одного уровня косвенного обращения.
Насколько я знаю, нет возможности записать что-нибудь вроде std::pack.
I've tried to solve the problem using T pack and aliasing single L and R. [...]
В вашем коде T... всегда будет пустым, поскольку он ничем не выводится. Значения параметров шаблона по умолчанию для L и R игнорируются, поскольку они выводятся при вызове функции.
Вам понадобится что-то вроде:
template<
typename... T,
typename = std::enable_if_t<(... && std::is_same_v<int, T>)>
>
int F(T...){
return 0x70D0;
}
В C++ 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;
}
Можно уронить decay_t<T>, так как вы принимаете по стоимости (decay_t<T> будет просто T)
@Barry: исправлено, также добавлено возможное решение C++ 20.
lol, у меня есть соблазн удалить свой голос за то, что я серьезно предложил это ;-)
std::tuple можно использовать в воображении очень похоже на этот гипотетический std::pack.
Слишком поздно играть?
Is it possible to create template parameter pack that can be folded to avoid writing same fragment of code multiple times?
Насколько мне известно, не в самом 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
}
Этот шаблон работает намного лучше, если вы определите isSameList для возврата этого объекта, поэтому вы можете заменить decltype(f()){} только на f().
@Barry - Ты прав: так проще и элегантнее. Спасибо!
У вас это почти было:
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
}
Я голосую за то, чтобы закрыть этот вопрос как не по теме, потому что, по-видимому, ОП больше не хочет, чтобы это было?