NSK*_*NSK 15 c++ templates for-loop compile-time-constant template-classes
我有一个像
template <size_t N>
class A
{
template <size_t N>
someFunctions() {};
};
Run Code Online (Sandbox Code Playgroud)
现在我想创建类的实例并在 for 循环中为一组许多值调用其中的函数,例如
// in main()
int main()
{
for (int i = 1; i <= 100; i++)
{
const int N = i; // dont know how to do this
A<N> a;
a.functionCalls();
}
}
Run Code Online (Sandbox Code Playgroud)
这该怎么做?希望有一种方法可以做到这一点。
Gui*_*cot 11
这将需要称为 a 的东西template for,它是扩展语句将采用的预期形式,它看起来像一个 for 循环,但实际上是一个函数中的模板块,它被多次实例化。
当然,有一个解决方法。我们可以滥用泛型 lambda 来声明某种本地模板化块并自己实例化它:
template <typename T, T... S, typename F>
constexpr void for_sequence(std::integer_sequence<T, S...>, F f) {
(static_cast<void>(f(std::integral_constant<T, S>{})), ...);
}
Run Code Online (Sandbox Code Playgroud)
这个函数接受一个整数序列,并F根据序列的长度实例化 lambda 。
它是这样使用的:
for_sequence(std::make_index_sequence<100>(), [](auto N) { /* N is from 0 to 99 */
A<N + 1> a; /* N + 1 is from 1 to 100 */
a.functionCalls();
});
Run Code Online (Sandbox Code Playgroud)
在这里,N可以作为模板参数发送,因为它是一个具有 constexpr 转换运算符到整数类型的对象。更准确地说,它的std::integral_constant价值越来越大。
The N needs to be compile-time constant, which is with a normal for loop is not possible.
But, there are many workarounds. For instance, inspired by this SO post, you can do something like the following. (See a Live demo)
template<size_t N>
class A
{
public:
// make the member function public so that you can call with its instance
void someFunctions()
{
std::cout << N << "\n";
};
};
template<int N> struct AGenerator
{
static void generate()
{
AGenerator<N - 1>::generate();
A<N> a;
a.someFunctions();
}
};
template<> struct AGenerator<1>
{
static void generate()
{
A<1> a;
a.someFunctions();
}
};
int main()
{
// call the static member for constructing 100 A objects
AGenerator<100>::generate();
}
Run Code Online (Sandbox Code Playgroud)
Prints 1 to 100
In c++17, the above can be reduced to a single template AGenerator class(i.e. specialization can be avoided), using if constexpr. (See a Live demo)
template<std::size_t N>
struct AGenerator final
{
static constexpr void generate() noexcept
{
if constexpr (N == 1)
{
A<N> a;
a.someFunctions();
// .. do something more with `a`
}
else
{
AGenerator<N - 1>::generate();
A<N> a;
a.someFunctions();
// .. do something more with `a`
}
}
};
Run Code Online (Sandbox Code Playgroud)
Output:
1
2
3
4
5
6
7
8
9
10
Run Code Online (Sandbox Code Playgroud)
In case of providing the range of iteration, you could use the following.(See a Live demo)
template<std::size_t MAX, std::size_t MIN = 1> // `MIN` is set to 1 by default
struct AGenerator final
{
static constexpr void generate() noexcept
{
if constexpr (MIN == 1)
{
A<MIN> a;
a.someFunctions();
// .. do something more with `a`
AGenerator<MAX, MIN + 1>::generate();
}
else if constexpr (MIN != 1 && MIN <= MAX)
{
A<MIN> a;
a.someFunctions();
// .. do something more with `a`
AGenerator<MAX, MIN + 1>::generate();
}
}
};
int main()
{
// provide the `MAX` count of looping. `MIN` is set to 1 by default
AGenerator<10>::generate();
}
Run Code Online (Sandbox Code Playgroud)
Outputs the same as the above version.
实现此目的的一种方法是使用模板元编程,如下所示:
#include <iostream>
template <std::size_t N>
struct A {
void foo() { std::cout << N << '\n'; }
};
template <std::size_t from, std::size_t to>
struct call_foo {
void operator()() {
if constexpr (from != to) {
A<from + 1>{}.foo();
call_foo<from + 1, to>{}();
}
}
};
int main() { call_foo<0, 100>{}(); }
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
412 次 |
| 最近记录: |