是否可以创建可折叠(※fold expression)模板parameter pack?
请考虑以下示例(带有两个类型为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;
}
是否可以创建可折叠的模板参数包,以避免多次编写同一段代码( ie std::is_same_v
)?
使用SFINAE可以简化下面std::pack
的内容吗?
typename = std::enable_if_t<(... && std::is_same_v<int, std::decay_t<std::pack<L, R>>>)>
我尝试使用T
压缩包并为单个L
和R
加上别名来解决该问题。
但是对于某些原因,以下代码可以在MSVC 15.9.4 + 28307.222上编译并运行而不会出现错误(第二个F
函数调用的第二个参数,衰减,不等于int
):
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
(衰减)参数的函数)?
答案 0 :(得分:3)
是否可以创建可折叠的模板参数包,以避免多次编写相同的代码片段?
到位了吗?不在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;
}
在C ++ 20中,您应该能够如下使用lambda:
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;
}
答案 1 :(得分:1)
玩太晚了吗?
是否可以创建可折叠的模板参数包,以避免多次编写相同的代码片段?
据我所知,F()
本身还没有。
但是您可以例如在调用函数的列表中重新打包类型。
我的意思是……如果您声明定义(仅声明:由于仅用于下面的功能[编辑:如Barry所建议(感谢)定义了该功能,简化了使用] 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
}
答案 2 :(得分:1)
您几乎拥有它:
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
}