반응형

 

std::pair는 두 개의 변수나 객체를 하나로 묶어 전달 할 때 사용된다.

 

1. 사용법

#include <utility>

std::pair< var-type1, var-type2 > var;

 

(1) 인자

  1-1) var-type : 변수나 객체의 타입을 지정

 

2. 사용 예제

#include <iostream>
#include <vector>
#include <utility>
#include <tuple>

using Type = std::pair<int, std::string>;

void print(const Type& param)
{
    std::cout << param.first << " = " << param.second << std::endl;
}

int main()
{
    // 선언과 함께 값 추가
    std::pair<int,std::string> p1{1, "one"};
    // 값에 직접 접근 (first, second)
    std::cout << p1.first << " = " << p1.second << std::endl; // 1 = one

    // std::make_pair를 사용하여 값 추가
    std::pair<int,std::string> p2{std::make_pair<int,std::string>(2, "two")};
    // std::get을 사용하여 값에 접근
    std::cout << std::get<0>(p2) << " = " << std::get<1>(p2) << std::endl; // 2 = two

    // auto를 사용하여 값에 접근
    auto& [num, str] = p1;
    std::cout << num << " = " << str << std::endl; // 1 = one

    // std::tie를 사용하여 값에 접근
    // #include <tuple> 필요
    int n{0};
    std::string s{};
    std::tie(n, s) = p2;
    std::cout << n << " = " << s << std::endl; // 2 = two

    // 벡터와 함께 사용
    std::vector<Type> vPair;
    vPair.emplace_back(p1);
    vPair.emplace_back(p2);
    vPair.emplace_back(std::make_pair<int,std::string>(3, "three"));
    vPair.emplace_back(Type(4, "four"));

    for (const Type& v : vPair) print(v);

    // 값 수정
    p1.first = 11;
    p1.second = "eleven";
    print(p1); // 11 = eleven

    return 0;
}


 
 
 

 

 

 

 

 

반응형
반응형

일반 배열은 길이 정보가 없어서 인자로 넘기려면 길이 정보를 같이 넘겨야 하고, 인덱스를 조금만 벗어나도 Buffer Overflow 와 같은 문제가 발생하므로 안전하지 않다.

C++20 이후에는 모든 연속 객체(배열, 문자열, 벡터, ...)를 안전하게 참조할 수 있도록 해주는 std::span을 사용할 수 있다.

연속 객체를 std::span으로 참조하게 되면 순차 컨테이너에서 제공하는 함수를 사용할 있다. (길이 정보와 반복자를 가짐)

 

1. 사용법

#include <span>

std::span< var-type > var; // 동적 길이를 가지는 span
std::span< var-type, size > var; // 정적 길이를 가지는 span

 

(1) 인자

  1-1) var-type : 변수나 객체의 타입을 지정

  1-2) size : span 사이즈를 지정하여 정적 span으로 사용

 

2. 사용 예제

#include <iostream>
#include <string>
#include <span>

template <typename T>
void printContainer(const std::span<T>& param)
{
    if (param.empty())
    {
        std::cout << "empty." << std::endl;
        return;
    }

    std::cout << "value:";
    for (const auto& v : param)
    {
        std::cout << " " << v;
    }
    std::cout << ", size: " << param.size() << std::endl;
}

int main()
{
    int iArr[5]{1,2,3,4,5};

    // 배열을 정적 span으로 설정
    std::span<int, 5> spArr{iArr};
    for (auto it = spArr.begin(); it != spArr.end(); ++it)
    {
        std::cout << *it << std::endl; // 1 2 3 4 5
    }

    // 배열을 동적 span으로 설정하여 인자로 사용
    printContainer(std::span<int>{iArr}); // value: 1 2 3 4 5, size: 5

    // 문자열을 동적 span으로 설정
    std::string pStr{"abcdefg"};
    std::span<char> spStr{pStr};
    printContainer(spStr); // value: 1 2 3 4 5, size: 5

    // 빈 span을 인자로 사용
    printContainer(std::span<int>{}); // empty.

    return 0;
}


 
 

 

 

 

 

반응형
반응형

bool 변수의 값이 false일 경우에만 특정 작업을 수행하고, true로 변경하는 경우가 빈번하게 발생한다.

기존에는 보통 아래와 같이 코드를 작성했다.

bool isFirst{false};

if (isFirst == false)
{
    // 작업을 수행
    ...
    ...
    isFirst = true;
}

 

C++14 이후에는 std::exchange를 사용하여 간결한 코드로 작성할 수 있으며, bool형 이외의 변수값을 변경할 수도 있다.

 

1. 사용법

#include <utility>

std::exchange( var, new-value )

 

(1) 인자

  1-1) var : 값을 변경할 변수나 객체

  1-2) new-value : 변경할 값

(2) 반환값 : 변경전의 var 값

 

2. 사용 예제

bool isFirst{false};

if (std::exchange(isFirst, true) == false)
{
    // 작업을 수행
    ...
    ...
}

 

3. 사용 예제 (컨테이너에 사용)

#include <iostream>
#include <utility>
#include <vector>

template <typename T>
void printContainer(const T& pContainer)
{
    for (const auto& v : pContainer)
    {
        std::cout << v << " ";
    }
    std::cout << std::endl;
}

int main()
{
    std::vector<int> vec{};

    // vector에 값을 저장
    std::exchange(vec, {1,2,3,4});
    printContainer(vec); // 1 2 3 4

    // vector의 값을 변경
    std::vector<int> oldVec{std::exchange(vec, {5,6,7,8})};
    printContainer(oldVec); // 1 2 3 4
    printContainer(vec); // 5 6 7 8

    return 0;
}

 

4. 사용 예제 (함수에 사용)

#include <iostream>
#include <utility>
#include <functional>

int main()
{
    std::function<void()> fFunc{[](){
        std::cout << "Original Function" << std::endl;
    }};
    fFunc(); // Original Function

    std::function<void()> fOldFunc{std::exchange(fFunc, [](){
        std::cout << "New Function" << std::endl;
    })};
    fFunc(); // New Function
    fOldFunc(); // Original Function
    
    return 0;
}


 

 

반응형
반응형

보통 함수를 실행한 후 결과값은 하나만 반환받을 수 있다.

함수 실행 결과와 결과값이 모두 필요할 경우에는 함수의 인자로 참조나 포인터 변수를 전달해야 했다.

C++17 이후에는 std::optional을 사용해서 함수의 반환값으로 [함수 실행 결과]와 [결과값]을 한번에 전달받을 수 있다.

 

1. 사용법

#include <optional>

std::optional< var-type > var-name;

 

(1) 인자

  1-1) var-type : 함수 실행 결과값의 타입을 지정

 

2. 사용 예제

#include <iostream>
#include <optional>
#include <string>

std::optional<std::string> toUpper(const std::string& pStr)
{
    if (pStr.empty() == true)
    {
        return std::nullopt;
    }

    std::string str{pStr};
    std::transform(str.begin(), str.end(), str.begin(), [](const char c) {
        return std::toupper(c);
    });

    return std::make_optional<std::string>(str); // return str; 로 대체 가능
}

void printResult(const std::optional<std::string>& pRet)
{
    if (pRet == std::nullopt) // (pRet.has_value() == false)로 대체 가능
    {
        std::cout << "failed !!!" << std::endl;
    }
    else
    {
        std::cout << *pRet << std::endl; // pRet.value()로 사용 가능
    }
}

int main()
{
    std::optional<std::string> ret{toUpper("abcdefg")};
    printResult(ret); // ABCDEFG

    ret = toUpper("");
    printResult(ret); // failed !!!

    return 0;
}


 

반응형
반응형

일반 함수는 [반환형], [함수 이름], [인수] 를 입력하여 선언한다. 

하지만 람다 함수는 이름이 없는 익명 함수로써 아래의 형태로 선언하여 사용하며, std::function 과 함께 사용시 재사용도 가능하다. 

(참고 : std::function - 함수 포인터를 대체하는 키워드)

 

1. 사용법

- 람다 함수는 캡처(Capture), 인자(Parameter), 반환형(Return-Type), 바디(Body) 로 구성되어 있다.
- 캡처와 인자는 콤마(,)로 구분하여 여러 개 지정할 수 있다.

[capture] (parameter) -> return-type { body };

 

(1) 캡처(Capture)

- 캡처는 람다 함수에서 사용할 변수나 상수를 참조나 복사의 형태로 찍어오는 것이다.
- 전역 변수를 참조로 캡처할때는 [&], 복사로 캡처할때는 [=]를 사용한다.
- 지역 변수를 참조로 캡처할때는 [&변수명], 복사로 캡처할때는 [=변수명]을 사용한다.

[&]() { return; } // 모든 변수를 참조로 캡처
[=]() { return; } // 모든 변수를 복사로 캡처
[&var1, var2]() { return; } // var1은 참조, var2는 복사로 캡처
[=, &var1]() { return; } // var1만 참조로 캡처하고, 다른 변수는 복사로 캡처
[&, var2]() { return; } // var2만 복사로 캡처하고, 다른 변수는 참조로 캡처

 

- 복사로 캡처된 변수는 기본적으로 constexpr 타입으로 지정되어 값의 변경이 불가하다.

- mutable로 선언하면 값의 변경이 가능하다.

int var1{0};

[var1]() {
    var1 = 999; // 에러!!! - var1은 constexpr 타입이므로 변경이 불가
}();
[var1]() mutable {
    var1 = 999; // var1은 mutable로 선언되어 변경이 가능, 단 실제 값은 변하지 않음
    std::cout << var1 << std::endl; // 999
}();

std::cout << var1 << std::endl; // 0

 

(2) 인자(Parameter)

- 일반 함수의 인자처럼 람다 함수에서 사용할 인자를 지정한다.

[](int a) -> int { return a; } // 1개의 인자를 설정
[](int a, int b) -> int { return (a+b); } // 2개의 인자를 설정


(3) 반환형(Return-Type)

- 람다 함수의 실행 결과를 반환할 반환 타입을 지정한다.


(4) 바디(Body)

- 람다 함수에서 수행할 작업을 기술한다.

 

2. 사용 예제

#include <iostream>
#include <functional>

int main()
{
    // 간단한 람다 함수
    []() {
        std::cout << "Simple Lamda Function" << std::endl;
    }();
    
    // 인자 2개를 더해서 sum에 저장하고, 더한 값을 반환하는 람다 함수
    int sum{0};
    // std::function 에 람다 함수를 정의
    std::function<int(int,int)> fSum{[&sum](int a, int b) -> int {
        sum = a + b;
        return sum;
    }};

    std::cout << fSum(10, 20) << std::endl; // 30
    std::cout << sum << std::endl; // 30
    
    return 0;
}

 

3. 사용 예제 (클래스에서 사용)

#include <iostream>
#include <functional>
#include <string>

class Person
{
public:
    Person(std::string&& pName, int pAge, std::function<std::string(std::string&, int)>&& pFunc)
        : mName(std::move(pName))
        , mAge(pAge)
        , mTagFunc(std::move(pFunc)) // 람다 함수로 전달받은 임시 함수(r-value)를 std::move를 사용해 저장
    {
        // 출력 람다 함수에서 클래스의 멤버 변수를 사용하기 위해 this를 캡처한다.
        mPrintFunc = [this]() {
            std::cout << "Name: " << mName << ", Age: " << mAge
                << ", Tag: " << mTag << std::endl;
        };
    }

    void executeTagFunc()
    {
    	// 태그 생성 람다 함수 호출
        mTag = mTagFunc(mName, mAge);
    }

    void executePrintFunc()
    {
    	// Person 정보 출력 람다 함수 호출
        mPrintFunc();
    }

private:
    std::function<std::string(std::string&, int)> mTagFunc{};
    std::function<void()> mPrintFunc{};

    std::string mName{};
    std::string mTag{};
    int mAge{0};
};

int main()
{
    // 객체 생성시 [이름], [나이], [태그 생성 함수]를 인자로 받음
    Person ps("Simson", 44, [](std::string& pName, int pAge) -> std::string {
        return std::string(pName + "-" + std::to_string(pAge));
    });

    ps.executeTagFunc();
    ps.executePrintFunc();

    return 0;
}


 

반응형

+ Recent posts