for 루프에서 다른 유형의 두 변수를 선언 할 수 있습니까?


240

C ++에서 for 루프의 초기화 본문에서 다른 유형의 변수 두 개를 선언 할 수 있습니까?

예를 들면 다음과 같습니다.

for(int i=0,j=0 ...

두 정수를 정의합니다. 나는 정의 할 수 intchar초기화 몸을? 이것은 어떻게 이루어 집니까?


3
g ++-4.4 ( -std=c++0x) 형식은 for(auto i=0, j=0.0; ...가능하지만 g ++-4.5에서는 c ++ 0x 텍스트와 일치하도록이 가능성이 제거되었습니다.
rafak

답변:


133

C ++ 17 : 예! 구조적 바인딩 선언을 사용해야합니다 . 이 구문은 gcc 및 clang에서 수년 동안 지원되었습니다 (gcc-7 및 clang-4.0 이후) ( clang live 예제 ). 이를 통해 다음과 같이 튜플의 포장을 풀 수 있습니다.

for (auto [i, f, s] = std::tuple{1, 1.0, std::string{"ab"}}; i < N; ++i, f += 1.5) {
    // ...
}

위의 내용은 다음과 같습니다.

  • int i 로 설정 1
  • double f 로 설정 1.0
  • std::string s 로 설정 "ab"

#include <tuple>이런 종류의 선언 을 확인하십시오 .

유형 이름을 지정하려면을 사용하여 tuple입력 한대로 모두 유형 을 입력 하여 정확한 유형을 지정할 수 있습니다 std::string. 예를 들면 다음과 같습니다.

auto [vec, i32] = std::tuple{std::vector<int>{3, 4, 5}, std::int32_t{12}}

이에 대한 구체적인 적용은지도를 반복하고 키와 가치를 얻는 것입니다.

std::unordered_map<K, V> m = { /*...*/ };
for (auto& [key, value] : m) {
   // ...
}

여기에 실제 예를 참조 하십시오


C ++ 14 : type-based를 추가하여 C ++ 11 (아래)과 동일하게 수행 할 수 있습니다 std::get. 따라서 std::get<0>(t)아래 예 대신 을 사용할 수 있습니다 std::get<int>(t).


C ++ 11 : 둘 이상의 객체 std::make_pair뿐만 아니라이를 수행 할 수 있습니다 std::make_tuple.

for (auto p = std::make_pair(5, std::string("Hello World")); p.first < 10; ++p.first) {
    std::cout << p.second << std::endl;
}

std::make_pair에서 두 개의 인수를 반환합니다 std::pair. 요소는 액세스 할 수 있습니다 .first.second.

두 개 이상의 객체의 경우 std::tuple

for (auto t = std::make_tuple(0, std::string("Hello world"), std::vector<int>{});
        std::get<0>(t) < 10;
        ++std::get<0>(t)) {
    std::cout << std::get<1>(t) << std::endl; // cout Hello world
    std::get<2>(t).push_back(std::get<0>(t)); // add counter value to the vector
}

std::make_tuplevaridic 템플릿은 여러 가지 인수로 구성된 튜플을 구성합니다 (물론 기술적 제한이 있음). 요소는 인덱스를 사용하여 액세스 할 수 있습니다std::get<INDEX>(tuple_object)

for 루프 본문 내에서 객체의 별칭을 쉽게 지정할 수 있지만 여전히 for .first또는 std::get루프 조건 및 업데이트 식 을 사용해야 합니다.

for (auto t = std::make_tuple(0, std::string("Hello world"), std::vector<int>{});
        std::get<0>(t) < 10;
        ++std::get<0>(t)) {
    auto& i = std::get<0>(t);
    auto& s = std::get<1>(t);
    auto& v = std::get<2>(t);
    std::cout << s << std::endl; // cout Hello world
    v.push_back(i); // add counter value to the vector
}

C ++ 98 및 C ++ 03 의 유형 이름을 명시 적으로 지정할 수 있습니다 std::pair. 그러나 이것을 두 가지 이상의 유형으로 일반화하는 표준 방법은 없습니다.

for (std::pair<int, std::string> p(5, "Hello World"); p.first < 10; ++p.first) {
    std::cout << p.second << std::endl;
}

5
C ++ 17을 수행하는 경우 make_and를 삭제할 수도 있습니다 std::pair(1, 1.0).
Marc Glisse

털이의 C ++ (14) 스타일 튜플 / 쌍 사업 - 모든 좋은 (아마, upvoted),하지만 :) 기괴한 외모
mlvljr

3
요컨대 가능하지만 예쁘지는 않을 것입니다.
일부 프로그래머 친구

네, 예쁘지는 않지만 마약입니다! 튜플 같은 것을 절대적으로 즐겼습니다. :) 그러나 실제로 그것은 C ++에서 for 루프의 매우 직관적이지 않은 구문 품질이며, 30 분 이상 두통을 주어 마침내
구글이

@aderchox 오해를 명확히 할 수 있다면 답을 업데이트 할 수 있습니다
Ryan Haining

276

아니요-그러나 기술적으로 해결 방법이 있습니다 (강제하지 않으면 실제로 사용하지는 않습니다).

for(struct { int a; char b; } s = { 0, 'a' } ; s.a < 5 ; ++s.a) 
{
    std::cout << s.a << " " << s.b << std::endl;
}

3
이것은 VS 2008에서 컴파일되지는 않지만 Comeau online에서 수행됩니다. ;-)
JRL

7
@ JRL : 아, VS2005도 마찬가지입니다. VC ++의 또 다른 비준수 기능은 추측합니다.
Georg Fritzsche

3
나는 Perl에서 동등한 작업을 수행했습니다. 그래도 C ++의 코드 검토를 통해 이와 같은 몰래 시도하지 않았습니다.
John

21
c ++ 11을 사용하면 기본값을 사용하여이 예제를 더 짧게 만들 수 있습니다.struct { int a=0; char b='a'; } s;
Ryan Haining

1
이 답변은 답변의 요구 사항을 충족하지만 가독성 POV에서 @MK를 선호합니다. 답변입니다. MK의 솔루션은 중괄호를 추가하여 범위를 해결합니다.
Trevor Boyd Smith

221

불가능하지만 다음을 수행 할 수 있습니다.

float f;
int i;
for (i = 0,f = 0.0; i < 5; i++)
{
  //...
}

또는 명시 적으로 범위 제한 fi추가 괄호를 사용하여 :

{
    float f; 
    int i;
    for (i = 0,f = 0.0; i < 5; i++)
    {
       //...
    }
}

나는 이것이 매우 오래된 질문이라는 것을 알고 있지만 두 번째 예에서와 같이 왜 주변에 여분의 괄호를 사용하여 설명 할 수 있습니까?
포드

13
@fizzisist는 f와 i의 범위를 사용되는 코드의 일부로 만 명시 적으로 제한합니다.
MK.

1
@MK. 고마워, 그게 내가 의심 한 것입니다. 설명하기 위해 답변을 편집했습니다.
포드

단 하나의 질문 : 왜 이런가요? : O
rohan-patel

'int a = 0, b = 4'처럼 작동하기 때문에 가정합니다. 즉, f와 i의 범위를 지정하면 해당 이름의 재사용을 막기 위해 유용 할 것 같지만 (공정한 이유로) 생성 된 코드는 일반적으로 최신 컴파일러 (이 경우)에서 동일합니다.
Asu

14

초기화에서 여러 유형을 선언 할 수는 없지만 여러 유형에 지정할 수 있습니다. EG

{
   int i;
   char x;
   for(i = 0, x = 'p'; ...){
      ...
   }
}

자신의 범위에서 선언하십시오.


3

최선의 접근 방식은 xian의 대답 이라고 생각 합니다.

그러나...


# 루프 for 중첩

이 방법은 더럽지 만 모든 버전에서 해결할 수 있습니다.

그래서 종종 매크로 함수에서 사용합니다.

for(int _int=0, /* make local variable */ \
    loopOnce=true; loopOnce==true; loopOnce=false)

    for(char _char=0; _char<3; _char++)
    {
        // do anything with
        // _int, _char
    }

추가 1.

declare local variables및에 사용할 수도 있습니다 initialize global variables.

float globalFloat;

for(int localInt=0, /* decalre local variable */ \
    _=1;_;_=0)

    for(globalFloat=2.f; localInt<3; localInt++) /* initialize global variable */
    {
        // do.
    }

추가 2.

좋은 예 : 매크로 기능 사용.

( for-loop-macro이므로 최상의 접근 방식을 사용할 수없는 경우 )

#define for_two_decl(_decl_1, _decl_2, cond, incr) \
for(_decl_1, _=1;_;_=0)\
    for(_decl_2; (cond); (incr))


    for_two_decl(int i=0, char c=0, i<3, i++)
    {
        // your body with
        // i, c
    }

# 진술 문

if (A* a=nullptr);
else
    for(...) // a is visible

0또는로 초기화 nullptr하려면이 트릭을 사용할 수 있습니다.

그러나 나는 열심히 읽는 때문에 이것을 권장하지 않습니다.

그리고 버그처럼 보입니다.


어떤 사람들이 다른 사람들과 어떻게 다르게 생각하는지 놀라게하는 것은 결코 끝나지 않습니다. 나는 그런 이상한 생각을 한 적이 없었을 것입니다. 재미있는 아이디어.
Dr. Person Person II

1

다중 for 루프 중첩과 관련된 다른 방법은 "for 루프에서 두 유형의 변수를 정의하는 방법이 있습니까? "를 참조하십시오 . Georg의 "struct trick"에 비해 다른 방법의 장점은 (1) 정적 및 비 정적 로컬 변수를 혼합 할 수 있고 (2) 복사 할 수없는 변수를 가질 수 있다는 것입니다. 단점은 읽기가 훨씬 적고 효율성이 떨어질 수 있다는 것입니다.


-2

매크로를 정의하십시오.

#define FOR( typeX,x,valueX,  typeY,y,valueY,  condition, increments) typeX x; typeY y; for(x=valueX,y=valueY;condition;increments)

FOR(int,i,0,  int,f,0.0,  i < 5, i++)
{
  //...
}

변수 범위도 이런 식으로 for 루프 내에 있지 않습니다.


{and를 사용하여 매크로의 코드를 별도의 범위로 줄임으로써 이러한 제한을 쉽게 극복 할 수 있습니다 }.
Nathan Osman

4
그는 할 수 없었습니다. 그의 매크로는 루프 바디를 감싸지 않습니다. 그는 추가 여는 브라켓을 추가 할 수 있지만 매크로를 사용할 때 "추가"닫기 브라켓이 필요합니다.
John

3
흥미로운 생각이지만, 이것을 고려하기 전에 다른 답변을 더 빨리 사용할 것입니다.
gregn3

-2

또한 C ++에서 아래와 같이 사용할 수 있습니다.

int j=3;
int i=2;
for (; i<n && j<n ; j=j+2, i=i+2){
  // your code
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.