Mutable, Auto

C++ 2019. 12. 25. 10:02
반응형

Mutable Data Members (C++)

이 키워드는 클래스에서 static도 const도 아닌 데이터 멤버에만 적용할 수 있습니다. 데이터 멤버를 mutable로 선언하면, const 멤버 함수에서 이 데이터 멤버에 대한 값 할당 작업이 허용됩니다.

구문

1
mutable member-variable-declaration;

설명

예를 들어, 다음 코드는 m_accessCount가 mutable로 선언되었기 때문에 오류 없이 컴파일되고, 따라서 GetFlag가 const 멤버 함수라도 GetFlag에서 이를 변경할 수 있습니다.

 

 

예제_

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class X
{
public:
   bool GetFlag() const
   {
      m_accessCount++;
      return m_flag;
   }
private:
   bool m_flag;
   mutable int m_accessCount;
};
 
int main()
{
}
 

 

 

자체예제_

일반 변수와 mutable 변수의 차이

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class A
{
    mutable int ia;
    int ib;
    
    
    A() : ia(0), ib(0)
    {
 
    }
 
    void TT() const
    {
        ia = 3;
        ib = 3// 이 부분에서 E0137 오류가 뜬다 - 내용은 수정할 수 없다고 한다.
    }
};
 
 
 
int main()
{
    return 0;
}
 
s

 


 

auto (C++)

 

auto (C++)

auto (C++) In this article --> Deduces the type of a declared variable from its initialization expression. Note The C++ standard defines an original and a revised meaning for this keyword. Before Visual Studio 2010, the auto keyword declares a variable in

docs.microsoft.com

초기화 된 표현식에서 선언된 변수의 유형을 유추합니다.

 

구문

1
2
auto declarator initializer;
[](auto param1, auto param2) {};
 

참고

auto 키워드는 컴파일러가 선언된 변수 또는 람다 식 매개 변수의 초기화 식을 사용하여 형식을 추론하도록 지시합니다.

 

다음과 같은 이점을 제공하므로 실제로 전환을 원하지 않는 한 대부분의 상황에서 auto 키워드를 사용하는 것이 좋습니다.

 

  • 견고성_Robustness: 표현식의 유형이 변경된 경우 (함수 반환 유형이 변경된 경우 포함) 작동합니다.

  • 수행_Performance: 변환(Conversion)이 발생하지 않음을 보장합니다.
  • 편의성_Usability: 유형 이름 맞춤법 불량 및 오타에 대해 걱정할 필요가 없습니다.
  • 효율성_Efficiency: 코딩이 더 효율적일 수 있습니다.

 

auto 사용을 원하지 않는 전환 사례:

 

  • 한정자를 지정하고 아무 것도 하지 않기를 원할 때
  • 템플릿 도우미 형의 표현 시 (예, valarray + valarray)

 

auto 키워드를 사용하려면 유형 대신 변수를 사용하여 변수를 선언하고 초기화 표현식을 지정하십시오. 또한 const, volatile, pointer (*), 참조 (&) 및 rvalue 참조 (&&)와 같은 지정자와 선언자를 사용하여 auto 키워드를 수정할 수 있습니다. 컴파일러는 초기화 표현식을 평가 한 다음, 변수 유형을 추론한 해당 정보를 사용합니다.

 

 

초기화 표현식은 할당 (등호 구문), 직접 초기화 (함수 스타일 구문), 연산자 new 표현식 또는 초기화 표현식이 범위 기반 선언문의 for-range-declaration 매개 변수가 될 수 있습니다 ( C ++) 문. 자세한 내용은이 문서 뒷부분의 초기화 프로그램 및 코드 예제를 참조하십시오.

 

auto 키워드는 유형에 대한 자리표시자이지만 그 자체가 유형이 아닙니다. 따라서 auto 키워드는 sizeof 및 (C ++ / CLI의 경우) typeid와 같은 캐스트 또는 연산자에서 사용할 수 없습니다.

 

 

 

 

유용성

auto 키워드는 복잡한 유형의 변수를 선언하는 간단한 방법입니다. 예를 들어, auto를 사용하여 초기화 표현식에 템플릿, 함수에 대한 포인터 또는 멤버에 대한 포인터가 포함된 변수를 선언할 수 있습니다.

 

또한 auto를 사용하여 변수를 람다식으로 선언하고 초기화 할 수도 있습니다. 람다 식의 형식은 컴파일러에만 알려져 있기 때문에 직접 변수의 형식을 선언할 수는 없습니다. 자세한 내용은 람다식의 예제를 참조하십시오.

 

 

 

 

Trailing Return Types_후행 반환 형식

decltype 타입 지정자와 함께 auto를 사용하여 템플릿 라이브러리를 작성할 수 있습니다. auto  decltype을 사용하여 반환 형식이 해당 템플릿 인수의 형식에 따라 달라지는 템플릿 함수를 선언합니다. 또는 auto  decltype을 사용하여 다른 함수에 대한 호출을 래핑하는 템플릿 함수를 선언한 다음 다른 함수의 반환 유형이 무엇이든 반환합니다. 자세한 내용은 decltype을 참조하십시오.

 

 

 

 

---------------------------- auto 예제 ----------------------

 

 

 

 

 

References and cv-qualifiers_참조 그리고 const, volatile 한정자

auto를 사용하면 참조, const 한정자 및 휘발성 한정자가 삭제됩니다. 다음 예제를 고려하십시오.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
 
using namespace std;
 
int main()
{
    int count = 10;
    int& countRef = count;
    auto myAuto = countRef;
 
    countRef = 11;
    cout << count << " ";
 
    myAuto = 12;
    cout << count << endl;
 
 
    const int TT = 10;
    auto CT = TT;
 
    CT = 11;
 
    cout << count << endl;
    cout << TT << " ";
    cout << CT;
}
 

결과_

1
2
11 11 
10 11
 

 

16줄 까지_

이전 예제에서 myAuto는 int 참조_referance형이 아니라 int 형이므로 참조 한정자가 auto로 삭제되지 않은 경우 출력은 11 11이 아니라 11 12입니다.

 

 

19줄 부터_

예제는 자체예제로서 const int auto로 받는 것을 실험해 본 것이다. 결과는 const int가 아닌 int 형으로 받았다. 따라서 20줄에 auto CT = TT; 절은 int CT = TT; 로 진행된다. 그래서 후에 CT값을 성공적으로 변환할 수 있는 것이었다.

 

 

단, 정말 참조형과 cv형을 못 받는 것은 아니다.
해당 예제를 다음과 같이 일부 수정을 하여 받으면 참조형과 const를 그대로 취할 수 있다.

 

 

수정 예제_

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
 
using namespace std;
 
int main()
{
    int count = 10;
    int& countRef = count;
    auto& myAuto = countRef; // 수정 부분
 
    countRef = 11;
    cout << count << " ";
 
    myAuto = 12;
    cout << count << endl;
 
 
    const int TT = 10;
    const auto CT = TT; // 수정 부분
 
    CT = 11;
 
    cout << endl;
    cout << TT << " ";
    cout << CT;
}
 
 

물론 이 코드는 20번째 const auto를 22번째에서 수정하려 하기 때문에 컴파일이 불가능하다. 만약 19줄 이후를 제외하고 이 예제를 실행한다면 이전에 얻지 못했던 결과를 얻을 수 있다.

 

19줄 이후 삭제 후 예제 출력_

1
11 12
 

 

 

성공적으로 9번줄에 선언된 countRef 참조형을 경유해 count를 바꾸었다.

 

 

 

중괄호 초기화_Braced initializers 를 활용한 타입 추론 (C++14)

다음 코드 예제에서는 중괄호를 사용하여 자동 변수를 초기화하는 방법을 보여줍니다. B와 C의 차이점과 A와 E의 차이점에 유의하십시오.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <initializer_list>
 
int main()
{
    // std::initializer_list<int>
    auto A = { 12 };
 
    // std::initializer_list<int>
    auto B = { 3 };
 
    // int
    auto C{ 4 };
 
    // C3535: cannot deduce type for 'auto' from initializer list'
    auto D = { 56.7 };
 
    // C3518 in a direct-list-initialization context the type for 'auto'
    // can only be deduced from a single initializer expression
    auto E{ 89 };
 
    return 0;
}
 
 

 

 

 

 

auto 중괄호 초기화 오류

 

해당 예제를 실제 프로젝트에 옮길 경우 오류코드가 다르기에 캡쳐를 해 보았다.

뭐... 그냥 코드만 다를 뿐 내용은 같았다.

 

 

 

 

제한사항과 오류 메세지

다음 표는 auto 키워드 사용에 대한 제한사항과 컴파일러가 방출하는 해당 진단 오류 메시지를 나열합니다.

 

오류번호 설명
C3530 auto 키워드는 다른 유형 지정자와 결합 될 수 없습니다.
C3531 auto 키워드로 선언된 심볼에는 초기화 프로그램이 있어야 합니다.
C3532 유형을 선언할 때 auto 키워드를 잘못 사용했습니다.
예를 들어, 메소드 리턴 유형 또는 배열을 선언했습니다.
C3533, C3539 매개 변수 또는 템플릿 인수는 auto 키워드로 선언 할 수 없습니다.
C3535 함수 또는 템플릿 매개 변수는 auto 키워드로 선언 할 수 없습니다.
C3536 해당 기호(Symbol-당연히 auto를 뜻함)는 초기화되기 전에 사용할 수 없습니다.
실제로 이것은 변수 자체를 초기화하는 데 사용할 수 없다는 것을 의미합니다.
C3537 auto 키워드로 선언된 유형으로는 캐스트(형변환)할 수 없습니다.
C3538 auto 키워드로 선언 된 선언자 목록의 모든 기호는 동일한 유형으로 확인되어야합니다.
자세한 내용은 선언 및 정의를 참조하십시오.
C3540, C3541 sizeof 및 typeid 연산자는 auto 키워드로 선언된 기호에 적용 할 수 없습니다.

 

 

활용 예제

이 코드 조각은 auto 키워드를 사용할 수있는 몇 가지 방법을 보여줍니다.

 

 

  • 다음 선언은 동일합니다.
    첫 번째 문에서 변수 j는 int 유형으로 선언됩니다.
    두 번째 문에서 변수 k는 초기화 표현식 (0)이 정수이기 때문에 유형 int로 추론됩니다.
1
2
int j = 0;  // Variable j is explicitly type int.
auto k = 0// Variable k is implicitly type int because 0 is an integer.
 

 

  • 다음 선언은 동일하지만 두 번째 선언은 첫 번째 선언보다 간단합니다.
    auto 키워드를 사용하는 가장 중요한 이유 중 하나는 단순성입니다.
1
2
map<int,list<string>>::iterator i = m.begin();
auto i = m.begin();
 

 

  • 다음 코드 단락에서는 for  for 열 루프가 시작될 때 iter 및 elem 변수의 유형을 선언합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// cl /EHsc /nologo /W4
#include <deque>
using namespace std;
 
int main()
{
    deque<double> dqDoubleData(100.1);
 
    for (auto iter = dqDoubleData.begin(); iter != dqDoubleData.end(); ++iter)
    { /* ... */ }
 
    // prefer range-for loops with the following information in mind
    // (this applies to any range-for with auto, not just deque)
 
    for (auto elem : dqDoubleData) // COPIES elements, not much better than the previous examples
    { /* ... */ }
 
    for (auto& elem : dqDoubleData) // observes and/or modifies elements IN-PLACE
    { /* ... */ }
 
    for (const auto& elem : dqDoubleData) // observes elements IN-PLACE
    { /* ... */ }
}
 
 

 

 

각각 원하는 &형 const & 형을 받을 수 있으며, 배열을 정상적으로 돈다. 더하여 이전에 int을 해야한다는 조건 같은 것도 없으며 단독으로도 성공적으로 이터레이터를 추론하여 준다. (실험 다 해봄 - 디버그 모드로 진입만 해도 아는 부분...)

 

 

 

순회 움짤

 

 

 

 

  • 다음 코드 단편은 new 연산자와 포인터 선언을 사용하여 포인터를 선언합니다.
1
2
double x = 12.34;
auto *= new auto(x), **= new auto(&x);
 

 

 

  • 다음 코드 단편은 각 선언문에 여러 기호를 선언합니다.
    각 명령문의 모든 기호는 동일한 유형으로 해석됩니다.
1
2
3
4
auto x = 1*= &x, **= &y; // Resolves to int.
auto a(2.01), *b (&a);         // Resolves to double.
auto c = 'a'*d(&c);          // Resolves to char.
auto m = 1&= m;            // Resolves to int.
 

 

  • 이 코드 조각은 조건 연산자 (? :)를 사용하여 변수 x를 200의 값을 갖는 정수로 선언합니다.
1
2
int v1 = 100, v2 = 200;
auto x = v1 > v2 ? v1 : v2;
 

 

해당 x는 int형이다.

 

 

 

  • 다음 코드 단편은 변수 x를 int 유형으로, 변수 y를 유형 const int에 대한 참조로, 변수 fp를 유형 int를 리턴하는 함수에 대한 포인터로 초기화합니다.
1
2
3
4
5
6
7
8
9
10
int f(int x) { return x; }
int main()
{
    auto x = f(0);
    const auto & y = f(1);
    int (*p)(int x);
    p = f;
    auto fp = p;
    //...
}
 

 

 

참고

auto Keyword
Keywords
/Zc:auto (Deduce Variable Type)
sizeof Operator
typeid
operator new
Declarations and Definitions
Examples of Lambda Expressions
Initializers
decltype

반응형

'C++' 카테고리의 다른 글

Decltype (C++) (declare type)  (0) 2019.12.25
volatile  (0) 2019.12.25
저장소 클래스 - Storage classes (static, extern, thread_local, register)  (0) 2019.12.25
Timer - 시간 측정기  (0) 2019.12.25
const*, constexpr**  (0) 2019.12.25
Posted by Kestone Black Box
,