Reputation:
Is it possible to create foldable (※ fold expression) template parameter pack?
Consider the following example (function that takes two arguments of type 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;
}
Is it possible to create template parameter pack that can be folded to avoid writing same fragment of code multiple times (ie std::is_same_v
)?
Something that represented as std::pack
below could simplify using SFINAE?
typename = std::enable_if_t<(... && std::is_same_v<int, std::decay_t<std::pack<L, R>>>)>
I've tried to solve the problem using T
pack and aliasing single L
and R
.
But for some reaon the following code compiles and runs without an error (second argument of second F
function call, decayed, does not equal int
) on 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 Also, did I miss something in the above code to make SFINAE work properly (filter functions with int, int
(decayed) arguments only)?
Upvotes: 2
Views: 216
Reputation: 6751
You almost had it:
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
}
or the variadic version:
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
}
Upvotes: 2
Reputation: 93364
Is it possible to create template parameter pack that can be folded to avoid writing same fragment of code multiple times?
In place? Not in C++17. You would have to wrap your types into some sort of template <typename...> struct typelist;
and then unwrap them somewhere else. This requires one layer of indirection.
There's no way to write anything like std::pack
as far as I know.
I've tried to solve the problem using T pack and aliasing single L and R. [...]
In your code, T...
will always be empty as it's not being deduced by anything. L
and R
's default template parameter values are ignored, as they are being deduced by the function call.
You need something like:
template<
typename... T,
typename = std::enable_if_t<(... && std::is_same_v<int, T>)>
>
int F(T...){
return 0x70D0;
}
In C++20, you should be able to use a lambda as follows:
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;
}
Upvotes: 4
Reputation: 66230
Is too late to play ?
Is it possible to create template parameter pack that can be folded to avoid writing same fragment of code multiple times?
Not in F()
itself, as far I know.
But you can repack the types, by example, in a list of a called function.
I mean... if you declare define (declare only: there isn't need of define it because is used only in a the following function [Edit: as suggested by Barry (thanks) defining the function simplify the use]decltype()
)
template <typename T, typename ... Ts>
constexpr auto isSameList ()
-> std::bool_constant<(... && std::is_same_v<T, std::decay_t<Ts>>)>
{ return {}; }
where you can use template folding, you can SFINAE to enable/disable F()
as follows
template <typename L, typename R,
std::enable_if_t<isSameList<int, L, R>(), bool> = true>
int F(L Left, R Right)
{ return 0x70D0; }
The following is a full compiling example
#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
}
Upvotes: 2