如何在for循环中使用const变量来生成模板类?


15

我有一个类似的代码

template <size_t N>
class A
{
    template <size_t N>
    someFunctions() {};
};

现在,我想创建该类的实例,并在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();
    }
}

这个怎么做?希望有一种方法可以做到这一点。


要作为一个模板参数N需要在constexpr其中,如果它是一个循环变量,情况并非如此
CoryKramer

您不能,A是否真的需要成为模板?
艾伦·比特尔斯

是的,出于某些原因,需要将A类作为模板,并且它是某种事物的模型,因此必须成为模板类
nachiappan venkatesh 19/12/5

Answers:


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>{})), ...);
}

此函数采用整数序列,并将λ实例化的F时间与序列的长度一样多。

它的用法如下:

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();
});

在这里,N可以作为模板参数发送,因为它是一个具有将constexpr转换为整数类型的运算符的对象。更确切地说,它的std::integral_constant价值不断提高。

现场例子


3
啊。当我看到这样的模板乐趣时,我只知道我稍后将不得不在没有调用堆栈的情况下对其进行调试,并且必须猜测发生了什么... :)
Michael Dorgan

目的是static_cast<void>什么?
Ayxan

2
@Ayxan避免了问题,当lambda f返回的类型会使逗号运算符重载时
Guillaume Racicot

@MichaelDorgan这就是我们需要的原因template for。像这样滥用语言结构总是更痛苦
Guillaume Racicot

@GuillaumeRacicot,或者我们需要比元编程模板更好的抽象。
Ajay Brahmakshatriya

5

N需要是编译时间常数,这与正常的for循环是不可能的。

但是,有许多解决方法。例如,受此SO帖子的启发,您可以执行以下操作。 观看现场演示

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();
}

打印1100


,可以使用将以上内容简化为单个模板AGenerator类(即,可以避免专门化)if constexpr观看现场演示

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`
        }
    }
};

输出

1
2
3
4
5
6
7
8
9
10

如果提供迭代范围,则可以使用以下内容。观看现场演示

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();
}

输出与上述版本相同。


4

在C ++ 20中,您可以使用模板lambda,因此您可以尝试以下操作

[]<int ... Is>(std::integer_sequence<int, Is...>)
 { (A<Is+1>{}.functionCall(), ...); }
   (std::make_integer_sequence<int, 100>{});

下面是一个完整的编译示例,该示例打印从0到99的所有数字

#include <utility>
#include <iostream>

int main()
 {
  []<int ... Is>(std::integer_sequence<int, Is...>)
   { (std::cout << Is << std::endl, ...); }
     (std::make_integer_sequence<int, 100>{});
 }

1

一种实现方法是使用模板元编程,如下所示:

#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>{}(); }

0

仅出于完整性-如果仅从循环调用函数的用途,是否真的需要对类或函数进行模板化?

如果是这样,并且您不想手写,请查看boost.hana。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.