저는 C ++ 98에서 C ++ 11로 이동하고 있으며 auto
키워드에 익숙해 졌습니다. auto
컴파일러가 유형을 자동으로 추론 할 수 있는지 명시 적으로 선언해야하는 이유가 궁금 합니다. 나는 C ++가 강력한 형식의 언어라는 것을 알고 있으며 이것은 규칙이지만 명시 적으로 변수를 선언하지 않고는 동일한 결과를 얻을 수 없었 auto
습니까?
저는 C ++ 98에서 C ++ 11로 이동하고 있으며 auto
키워드에 익숙해 졌습니다. auto
컴파일러가 유형을 자동으로 추론 할 수 있는지 명시 적으로 선언해야하는 이유가 궁금 합니다. 나는 C ++가 강력한 형식의 언어라는 것을 알고 있으며 이것은 규칙이지만 명시 적으로 변수를 선언하지 않고는 동일한 결과를 얻을 수 없었 auto
습니까?
답변:
명시 적을 삭제하면 auto
언어가 손상됩니다.
예 :
int main()
{
int n;
{
auto n = 0; // this shadows the outer n.
}
}
을 떨어 뜨리면 바깥쪽에 그림자auto
가 생기지 않는다는 것을 알 수 있습니다 .n
n := 0
새 변수를 도입하는 것과 같은 것을 분명히 사용할 수 있습니다 . auto
사용되는 이유 는 의견 기반 질문입니다.
:=
. (d) 이미 문법에 맞습니다. 여기에는 의견의 여지가 거의 없다고 생각합니다.
x = f()
새 변수를 선언하는 경우 (아직 존재 하지 않는 경우) 새 토큰이 필요하지 않습니다. f의 반환 값 유형을 가져옵니다. 변수를 명시 적으로 선언하려면 auto가 필요하지만 새 변수를 선언 할 위험이 줄어 듭니다. 실수로 (예 : 오타로 인해 ...).
귀하의 질문은 두 가지 해석을 허용합니다.
밧세바 는 첫 번째 해석에 대해 훌륭하게 대답 했고, 두 번째 해석에서는 다음을 고려하십시오 (지금까지 다른 선언이 없다고 가정하고 가상적으로 유효한 C ++).
int f();
double g();
n = f(); // declares a new variable, type is int;
d = g(); // another new variable, type is double
if(n == d)
{
n = 7; // reassigns n
auto d = 2.0; // new d, shadowing the outer one
}
그것은 것이 가능하지만 다른 언어는 ++ (물론, 따로 아마도 그림자 문제에서) ... 그것은하지 그래서 C에와 아주 잘 도망하고, (두 번째 해석의 의미에서) 지금 질문 : 왜 ?
이번에는 첫 번째 해석 에서처럼 대답이 분명하지 않습니다. 하지만 한 가지는 분명합니다. 키워드에 대한 명시적인 요구 사항은 언어를 더 안전하게 만듭니다 (이게 언어위원회가 결정을 내리게 한 이유는 모르겠지만 여전히 요점으로 남아 있습니다).
grummel = f();
// ...
if(true)
{
brummel = f();
//^ uh, oh, a typo...
}
더 이상의 설명이 필요하지 않다는 것에 동의 할 수 있습니까?
auto를 필요로하지 않는 더 큰 위험은 [하지만] 함수에서 멀리 떨어진 곳에 전역 변수를 추가하면 (예 : 헤더 파일에서) 로컬 선언이 의도했던 바를 바꿀 수 있다는 것입니다. 해당 함수의 범위 변수를 전역 변수에 할당 할 수 있습니다. 잠재적으로 비참한 (확실히 매우 혼란스러운) 결과를 초래합니다.
auto
내 생각에를 요구하지 않는 더 큰 위험은 함수에서 멀리 떨어진 곳 (예 : 헤더 파일)에 전역 변수를 추가하면 로컬 범위의 선언으로 의도 된 것을 바꿀 수 있다는 것입니다. 그 함수의 변수를 전역 변수에 할당 할 수 있습니다. 잠재적으로 비참한 (확실히 매우 혼란스러운) 결과를 초래합니다.
global <variable>
명령문 없이도 전역 변수에서 읽을 수 있습니다 .) 물론 C ++ 언어에 대한 더 많은 수정이 필요하므로 가능하지 않을 것입니다.
MOV R6 R5
SUB #nnn R6
PDP-11의 IIRC 는 R5가 프레임 포인터로 사용되고 R6이 스택 포인터라고 가정합니다. nnn은 필요한 스토리지 바이트 수입니다.
변수를 명시 적으로 선언하지 않고는 동일한 결과를 얻을 수 없었
auto
습니까?
필요한 이유를 이해하는 데 도움이되는 방식으로 질문을 약간 수정하겠습니다 auto
.
유형 자리 표시자를 명시 적으로 사용 하지 않고 동일한 결과를 얻을 수 없었습니까 ?
가능 하지 않았 나요 ? 물론 "가능"했습니다. 문제는 그렇게하기 위해 노력할 가치가 있는지 여부입니다.
유형 이름이없는 다른 언어의 대부분의 구문은 두 가지 방법 중 하나로 작동합니다. name := value;
변수를 선언하는 Go와 같은 방법 이 있습니다. 그리고 파이썬과 같은 방법 name = value;
이 있습니다.name
이전에 선언되지 않은 이 있습니다.
두 구문 중 하나를 C ++에 적용하는 데 구문 문제가 없다고 가정 해 봅시다 (이미 그 identifier
뒤에 오는 것을 볼 수 있지만:
C ++에서 "레이블 만들기"를 의미 함을 ). 그렇다면 자리 표시 자에 비해 잃는 것은 무엇입니까?
글쎄, 나는 더 이상 이것을 할 수 없다.
auto &name = get<0>(some_tuple);
참조, auto
항상 "가치"를 의미합니다. 참조를 얻으려면 명시 적으로&
. 그리고 할당 표현식이 prvalue이면 제대로 컴파일되지 않습니다. 할당 기반 구문에는 참조와 값을 구별하는 방법이 없습니다.
이제 주어진 값이 참조 인 경우 이러한 할당 구문이 참조를 추론하도록 만들 수 있습니다. 그러나 그것은 당신이 할 수 없다는 것을 의미합니다.
auto name = get<0>(some_tuple);
이 사본 의 객체를 생성 독립적 튜플에서 some_tuple
. 때로는 그것이 정확히 당신이 원하는 것입니다. 를 사용하여 튜플에서 이동하려는 경우 훨씬 더 유용합니다 auto name = get<0>(std::move(some_tuple));
.
좋습니다. 그래서 우리는이 구분을 설명하기 위해이 구문을 약간 확장 할 수 있습니다. 아마도 &name := value;
또는 &name = value;
같은 참조를 추론하는 것을 의미합니다 auto&
.
알았어 괜찮아. 이것에 대해 :
decltype(auto) name = some_thing();
아 맞다. C ++ 실제로이 두 자리를 : auto
와decltype(auto)
. 이 추론의 기본 개념은 마치 당신이 한 것처럼 정확하게 작동한다는 것 decltype(expr) name = expr;
입니다. 따라서 우리의 경우 some_thing()
객체 라면 객체를 추론 할 것입니다. some_thing()
참조 인 경우 참조를 추론합니다.
이것은 템플릿 코드에서 작업 할 때 함수의 반환 값이 정확히 무엇인지 확실하지 않을 때 매우 유용합니다. 이것은 포워딩에 유용하며 널리 사용되지 않더라도 필수적인 도구입니다.
이제 구문에 더 많은 것을 추가해야합니다. name ::= value;
의미 "무엇을decltype(auto)
. 나는 Pythonic 변형에 상응하는 것이 없습니다.
이 구문을 보면 실수로 잘못 입력하는 것이 쉽지 않습니까? 뿐만 아니라 자체 문서화가 아닙니다. decltype(auto)
전에 본 적이 없더라도 뭔가 특별한 일이 벌어지고 있다는 것을 적어도 쉽게 알 수있을만큼 크고 분명합니다. ::=
와 사이의 시각적 차이는:=
는 미미합니다.
그러나 그것은 의견입니다. 더 실질적인 문제가 있습니다. 이 모든 것은 할당 구문 사용을 기반으로합니다. 음 ... 할당 구문을 사용할 수없는 곳은 어떻습니까? 이렇게 :
for(auto &x : container)
그것을로 변경 for(&x := container)
합니까? 범위 기반 과 는 매우 다른 것을 말하는 것 같기 때문 입니다 for
. for
범위 기반이 아닌 일반 루프 의 이니셜 라이저 문인 것 같습니다.for
. 또한 추론되지 않은 경우와 다른 구문입니다.
또한 복사 초기화 (사용 =
)는 C ++에서 직접 초기화 (생성자 구문 사용 )와 동일하지 않습니다. 따라서 name := value;
경우에 작동하지 않을 수 auto name(value)
있습니다.
물론 :=
직접 초기화를 사용할 것이라고 선언 할 수 있지만 나머지 C ++의 작동 방식과는 상당히 일치하지 않습니다.
또한 한 가지 더 있습니다 : C ++ 14. 그것은 하나의 유용한 추론 기능을 제공했습니다 : 반환 유형 추론. 그러나 이것은 자리 표시자를 기반으로합니다. range-based와 매우 유사하게 for
기본적으로 특정 이름 및 표현식에 적용된 일부 구문이 아니라 컴파일러에 의해 채워지는 유형 이름을 기반으로합니다.
이 모든 문제는 동일한 소스에서 비롯됩니다. 변수 선언을위한 완전히 새로운 구문을 개발하고 있습니다. 자리 표시 자 기반 선언은 새로운 구문 을 만들 필요가 없었습니다 . 이전과 똑같은 구문을 사용하고 있습니다. 유형처럼 작동하지만 특별한 의미가있는 새 키워드를 사용하고 있습니다. 이것이 범위 기반 for
및 반환 유형 추론 에서 작동하도록 허용하는 것 입니다. 그것은 여러 형태를 가질 수있게 해준다 ( auto
vs. decltype(auto)
). 기타 등등.
자리 표시자는 문제에 대한 가장 간단한 해결책 인 동시에 실제 유형 이름 사용의 모든 이점과 일반성을 유지하기 때문에 작동합니다. 자리 표시 자처럼 보편적으로 작동하는 다른 대안을 생각해 냈다면 자리 표시 자만큼 간단 할 가능성은 거의 없습니다.
키워드 나 기호가 다른 맞춤법 자리 표시 자만 아니라면 ...
auto
선언 / 반환 값 추론 과 의미가 다르기 때문에 언급하지 않았습니다 .
auto
경우에 따라 삭제 될 수 있지만 불일치로 이어질 수 있습니다.먼저 지적했듯이 C ++의 선언 구문은 <type> <varname>
. 명시 적 선언에는 일부 유형 또는 그 자리에 적어도 선언 키워드가 필요합니다. 그래서 우리는 var <varname>
or declare <varname>
또는 something을 사용할 수 있지만 auto
C ++에서 오래 지속되는 키워드이며 자동 유형 추론 키워드의 좋은 후보입니다.
모든 것을 깨뜨리지 않고 할당으로 변수를 암시 적으로 선언 할 수 있습니까?
어쩔 땐 그래. 함수 외부에서는 할당을 수행 할 수 없으므로 선언에 할당 구문을 사용할 수 있습니다. 그러나 이러한 접근 방식은 언어에 불일치를 가져와 인적 오류로 이어질 수 있습니다.
a = 0; // Error. Could be parsed as auto declaration instead.
int main() {
return 0;
}
그리고 어떤 종류의 지역 변수에 관해서도 명시 적 선언은 변수의 범위를 제어하는 방법입니다.
a = 1; // use a variable declared before or outside
auto b = 2; // declare a variable here
모호한 구문이 허용 된 경우 전역 변수를 선언하면 갑자기 로컬 암시 적 선언이 할당으로 변환 될 수 있습니다. 이러한 전환을 찾으려면 모든 것을 . 충돌을 방지하려면 모든 전역에 대해 고유 한 이름이 필요합니다. 이는 범위 지정에 대한 전체 아이디어를 파괴합니다. 그래서 정말 나쁩니다.
구문은 모호하지 않고 이전 버전과도 호환되어야합니다.
auto가 삭제되면 문과 정의를 구분할 방법이 없습니다.
auto n = 0; // fine
n=0; // statememt, n is undefined.
auto
이미 키워드 (그러나 쓸모없는 의미) 였으므로 이름으로 사용하여 코드를 깨지 않았습니다. 이는 var
또는 과 같은 더 나은 키워드 let
가 대신 선택되지 않은 이유 입니다.
auto
는 실제로 이것에 대한 꽤 훌륭한 키워드입니다. 즉, 그것이 의미하는 바를 정확히 표현합니다. 즉, 유형 이름을 "자동 유형"으로 대체합니다. 같은 키워드로 var
또는 let
, 당신은 결과적으로 키워드를 필요로한다 해도 , 종류가 명시 적으로 지정 즉 var int n = 0
나 같은 것을 var n:Int = 0
. 이것은 기본적으로 Rust에서 수행되는 방법입니다.
auto
은 기존 구문의 맥락에서 확실히 탁월 하지만 var int x = 42
, 기본 변수 정의 var x = 42
와 int x = 42
같은 것이 역사적인 내용을 고려할 때 현재 구문보다 더 합리적 이라고 말할 수 있습니다. 그러나 그것은 대부분 맛의 문제입니다. 그러나, 당신이 옳습니다, 나는 나의 원래 코멘트에 "이유"대신에 "이유 중 하나"를
auto
에는 자동 유형 (표현식에 따라 다른 유형)이 있습니다.
이전 답변에 추가로, 옛 방귀에서 한 가지 추가 사항 : 어떤 식 으로든 선언하지 않고 새 변수를 사용하기 시작할 수 있다는 이점이 있다고 생각할 수 있습니다.
변수의 암시 적 정의 가능성이있는 언어에서는 특히 대규모 시스템에서 큰 문제가 될 수 있습니다. 하나의 오타를 작성하고 몇 시간 동안 만 디버그하여 의도하지 않게 값이 0 (또는 더 나쁨) 인 변수를 도입했음을 알 수 있습니다.- blue
vs bleu
, label
vs lable
... 정확한 검사 없이는 어떤 코드도 신뢰할 수 없습니다. 변수 이름.
사용하는 것만으로 auto
컴파일러와 유지 관리자 모두에게 새 변수를 선언하려는 의도임을 알립니다.
이런 종류의 악몽을 피하려면 FORTRAN에 '암시 적 없음'문이 도입되었습니다. 오늘날 모든 심각한 FORTRAN 프로그램에서 사용되는 것을 볼 수 있습니다. 그것을 가지지 않는 것은 단순히 ... 무섭습니다.