템플릿 클래스 생성을 위해 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는 정말 템플릿이어야합니까?
Alan Birtles

네, 클래스 A가 어떤 이유로 템플릿이되어야 할 필요가 있습니다. 그리고 그것은 무언가의 모델이므로 템플릿 클래스
여야합니다

답변:


11

이를 위해서는 확장 문template for예상되는 형식 인 for 라는 것이 필요 합니다. for 루프처럼 보이지만 실제로는 여러 번 반복되는 함수의 템플릿 블록입니다.

물론 해결 방법이 있습니다. 우리는 일반적인 람다를 남용하여 일종의 로컬 템플릿 블록을 선언하고 스스로 선언 할 수 있습니다.

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

여기에서 Nconstexpr 변환 연산자를 정수 유형으로 변환하는 오브젝트이므로 템플리트 매개 변수로 보낼 수 있습니다. 보다 정확하게 std::integral_constant는 값이 증가함에 따라

라이브 예


3
어. 이와 같은 템플릿 재미를 볼 때, 나는 단지 콜 스택없이 나중에 그것을 디버깅하고 무슨 일이 일어나고 있는지 추측해야한다는 것을 안다 ... :)
Michael Dorgan

의 목적은 static_cast<void>무엇입니까?
Ayxan

2
@Ayxan 피 문제 람다는 f타입을 반환 과부하 콤마 연산자
기욤 Racicot의

@MichaelDorgan 이것이 우리에게 필요한 이유 template for입니다. 이 같은 언어 구조를 남용하는 것은 항상 더 많은 고통
기욤 Racicot의

@GuillaumeRacicot 또는 메타 프로그래밍을위한 템플릿보다 더 나은 추상화가 필요합니다.
Ajay Brahmakshatriya

5

N요구는 통상 함께 컴파일 시정 될 for루프가 불가능하다.

그러나 많은 해결 방법이 있습니다. 예를 들어,이 SO post 에서 영감을 받아 다음과 같은 작업을 수행 할 수 있습니다. ( 실시간 데모 참조 )

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에서 템플릿 람다를 사용할 수 있으므로 다음과 같이 시도해 볼 수 있습니다.

[]<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를보십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.