2016-06-21 20 views
0

템플릿 함수 foo을 일련의 다른 (유형이 아닌) 매개 변수로 호출하고 싶습니다. 상한과 하한 사이의 연속적인 정수 값을 사용합니다. 예를 들어 :여러 매개 변수 값이있는 템플릿 함수 호출

template <int K> void foo(){ ... } 

int const UPPER = 10, LOWER = 5; 

for(int i = LOWER; i <= UPPER; i++) 
    foo<i>(); 

이, 물론, i은 컴파일 타임에 알려져 있지 않기 때문에 작동하지 않습니다. 내가 다음에 하나 개의 실행에서 UPPERLOWER 변경에 대한 의도 때문에 특히입니다

foo<5>(); foo<6>(); foo<7>(); foo<8>(); foo<9>(); foo<10>(); 

: 내가 좋아하는 뭔가를 작성하지 않고도 프로그램의 종류를 달성 할 수있는 방법을 찾고 있어요. 배열의 요소가 일정한 있지만, i가에 알 수없는, 다시

int const arr[6] = {5, 6, 7, 8, 9, 10}; 

for(int i = LOWER; i <= UPPER; i++) 
    foo<arr[i]>(); 

하지만, :

내 유일한 생각은 템플릿 매개 변수로 전송됩니다 정수의 일정한 배열을 만드는 것이 었습니다 컴파일 시간은 arr[i]이 아닙니다. 어떤 제안?

미리 감사드립니다.

+2

그것은 당신이 ['표준을 사용할 수 있습니다 같다 : : integer_sequence'] (http://en.cppreference.com/w/cpp/utility/integer_sequence) – NathanOliver

+0

foo()를' 구조체 foowrapper '템플릿에 넣을 수 있습니다. ? – lorro

답변

3

LowerUpper과 같은지 여부에 따라 두 템플릿과 std::enable_if 중 하나를 선택할 수 있습니다. 인 경우에는 아무 것도하지 않습니다. 그렇지 않으면 을 호출하고 Lower + 1Upper 매개 변수를 사용하여 재귀 호출합니다.

template <int Lower, int Upper> 
typename std::enable_if<Lower == Upper, void>::type callFoo() 
{ 

} 

template <int Lower, int Upper> 
typename std::enable_if<Lower != Upper, void>::type callFoo() 
{ 
    static_assert(Lower < Upper, "Lower must be less than or equal to Upper"); 

    foo<Lower>(); 
    callFoo<Lower + 1, Upper>(); 
} 

이 템플릿을 감안할 때, 다음 줄은 K5, 6, 7, 8, 9, 10에 대한 foo<K>()를 호출합니다.

callFoo<5, 11>(); 
+0

아주 우아한 솔루션입니다. 고맙습니다. – tmnol

+0

호기심에서이 코드가 이전 버전의 C++ (C++ 11 이전)와 호환 될 수있는 해결 방법에 대해 알고 있습니까? – tmnol

0

필자가 아는 한 템플릿은 컴파일하는 동안 실제 구조체로 해석되므로 함수를 인수로 int를 전달해야합니다.

+1

OP는 컴파일 타임에 정수를 알고 있습니다. 템플릿 인수로 사용할 수있는 컴파일 타임 루프에 해당하는 문제입니다. – chris

+0

알아,하지만이게 뭔지 몰랐어. @ NathanOliver는 내가 알지 못하는 것을 지적했다. std :: integer_sequence – MaciekGrynda

+0

@MaciekGrynda 정수를 함수의 인수로 전달할 수 있었다면 실제로 내 인생을 훨씬 쉽게 할 수 있었다. 그러나 질문의 ​​범위를 벗어나는 이유 때문에 나는 할 수 없습니다. – tmnol

3

당신은 0 오름차순에서 숫자의 컴파일 시간 목록을 가져올 std::integer_sequence을 활용하고 추가 할 수 있습니다 오프셋 :

// Here we take the lower bound and the sequence 0 to (Upper - Lower). 
// We call foo with each number in the sequence added to the lower bound. 
template<int Lower, int... Ints> 
void call_foo_with_range_helper(std::integer_sequence<int, Ints...>) { 
    // A common trick to expand the parameter pack without recursion or fold expressions 
    (void)std::initializer_list<int>{(foo<Lower + Ints>(), 0)...}; 
} 

// This simply makes it easier for the caller to use. 
// We take the lower and upper bounds only. 
template<int Lower, int Upper> 
void call_foo_with_range() { 
    call_foo_with_range_helper<Lower>(std::make_integer_sequence<int, Upper - Lower + 1>()); 
} 

int main() { 
    int const UPPER = 10, LOWER = 5; 

    call_foo_with_range<LOWER, UPPER>(); 
} 
+0

답변 해 주셔서 감사합니다[email protected]의 대답은 내가 이해하기 쉬운 시간을 가졌기 때문에 최선이라고 표시했다. (그리고 내 코드를 읽는 사람들도 그렇다고 가정한다.) 둘 다 좋은 해결책이다. – tmnol

+2

@TudorManole, 문제가 없습니다. 전체'initializer_list' 비지니스는 불행한 일이며 fold 표현식이 사용 가능하면'(foo (), ...);'로 대체 될 수 있습니다. 그 외에도,'std :: integer_sequence'는 정말로 감사하기 전에 몇 번 필요로하는 것들 중 하나입니다. 이 경우 작업의 대부분은 0부터 시작하는 범위가 아닌 모든 범위를 지원합니다. – chris