新手,刚开始学习 C++模板元编程
需求: 想实现这样一个简单的函数调用,对一个容器中的所有整数求和:
sum<IntList<1, 2, 3>>();
由于 C++标准中不允许函数模板来实现偏特化,所以我想用 concept/requires 来达到偏特化的需求。 我的实现如下:
#include <iostream>
template<int...N>
class IntList;
template<int...N>
concept IsIntList = IntList<N...>{};
template<typename T>
int sum() {
return 0;
}
template<int...N>
requires IsIntList<N...>
int sum() {
return (N + ...);
}
int main() {
std::cout << sum<IntList<1, 2>>() << std::endl;
return 0;
}
实际运行时并不能达到我想要的结果,实际在C++ Insights中输出如下:
#include <iostream>
template<int...N>
class IntList;
template<int...N>
concept IsIntList = IntList<N...>{};
template<typename T>
int sum() {
return 0;
}
/* First instantiated from: insights.cpp:21 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
int sum<IntList<1, 2> >()
{
return 0;
}
#endif
template<int...N>
requires IsIntList<N...>
int sum() {
return (N + ...);
}
int main()
{
std::cout.operator<<(sum<IntList<1, 2> >()).operator<<(std::endl);
return 0;
}
可以看出模板实例化时并没有对第二个sum
进行实例化,而是对第一个sum
实例化。
请问各位大佬,在这种情况下,如何使用 concept/requires 来正确的实现我的需求?
1
ink19 2022-01-08 14:50:28 +08:00
没有接触过 concept/requires 但是学过一些元编程,你这个想法可以用下面这个方法实现
```C++ template<int ...N> class IntList{}; template<typename T> class sum_impl; template<typename T> int sum() { return sum_impl<T>::value; } template<> class sum_impl<IntList<>> { public: const static int value = 0; }; template<int first, int ...other> class sum_impl<IntList<first, other...>> { public: const static int value = first + sum_impl<IntList<other...>>::value; }; ``` |
2
secondwtq 2022-01-08 16:09:11 +08:00
|
3
zeal7s OP @secondwtq 这个确实可行。
另外,我想问下 template<typename T> void sum() {} 其中的 T 如果我能确保它的类型是 IntList<int...N>,那么我可以在 sum 函数中对 T 进行包展开吗? 如果可以,那么如何把 T 变成 IntList<int... N>呢? |
4
secondwtq 2022-01-08 20:09:47 +08:00
@zeal7s 我随便写的 ...
换成 template<typename T = void> constexpr int sum(IntList<>) { return 0; } 应该也行 你要把 T 弄成 IntList 不是不行,但是你要展开就得想办法把模板参数拿出来。这个好像最后都要 boil down 到某种形式的 pattern matching ,你只有一个 T 的话是没法做的。 |
5
sarvatathagata 2022-01-08 22:14:22 +08:00
应该这么写吧,虽然这个 concept 永远为真……
#include <iostream> template<int...N> class IntList{}; template<int...N> concept IsIntList = requires{IntList<N...>{};}; template<int...N> requires IsIntList<N...> int sum() { return (N + ...); } int main() { std::cout << sum<1, 2>() << std::endl; return 0; } |