프로그래밍/c++

boost::variant(std::variant c++17) 사용하기

제페 2016. 8. 5. 03:38
반응형

boost::variant는 n개의 타입이 될 수 있는 타입이다. 

boost::any와의 차이점은 지정된 형태로만 될 수 있으며 any와는 다르게 타입 변환 시 동적 할당을 사용하지 않기 때문에 퍼포먼스가 좀 더 뛰어나다. 


boost::variant는 n개의 타입이 될 수 있는 타입이다. union의 c++판 업그레이드 버전 정도 되는 라이브러리라고 생각해도 괜찮다. 또, c++17에 표준으로 포함 되었으며 c++ 관련 커뮤니티에서의 반응도 긍정적이다. 일단 사용하는 방법이 깔끔하고 쉬우니까.

코드 >>

#include <boost/variant.hpp>

 

boost::variant<int, std::string, double> var;

 

// set

var = 0.01;

var = 123;

var = "hello";

 

// get

std::string s = boost::get<std::string>(var);



값을 얻을 땐 boost::get을 통해 얻어야 하며 잘못된 타입으로 get을 시도하면 런타임 예외가 발생한다. 

코드 >>

#include <boost/variant.hpp>

 

boost::variant<int, std::string, double> var;

 

// set

var = 0.01;

var = 123;

var = "hello";

 

// get

std::string s = boost::get<std::string>(var);



boost::variant<double, std::string> var = 0.01;

 

try

{

    std::string s = boost::get<std::string>(var);    // 런타임 예외!

    // std::vector v = boost::get<std::vector>(var); // 컴파일 타임 오류!

}

catch(const boost::bad_get& e)

{// 잘못된 variant 캐스트!

    // ...

}



예외가 찜찜하다면, get에 variant 인스턴스의 포인터를 건네면 실패 시 nullptr을 주는 식으로 체크를 하는 것도 가능하다. 

코드>>

boost::variant<double, std::string> var = "hello";

 

std::string* d = boost::get<double>(&var); // d는 nullptr이 된다.

std::string* s = boost::get<std::string>(&var); // s엔 정상적인 값이 들어간다.


방문자(Visitor)를 통한 연산을 지원하며, 이를 이용하면 사용자가 잘못된 get 캐스팅으로 인한 오류를 방지하고, 컨텐츠를 작성하는 부분을 좀 더 깔끔하게 만들 수도 있다. 주의 사항은 모든 

코드>>


class cprint : public boost::static_visitor<>

{

public:

    void operator()(const std::string& s) const

    {

        std::cout << s;

    }

    void operator()(const int& i) const

    {

        std::cout << i;

    }

    void operator()(const double& d) const

    {

        std::cout << d;

    }

    // or

    // template < typename T >

    // void operator()(const T& t) const

    // {

    //        std::cout << t;

    // }

};

 

// ..

 

boost::variant<int, double, std::string> var = "hello, hello";

 

boost::apply_visitor(cprint(), var); // 알맞는 게 출력된다.


마지막으로 for_each와 visitor를 이용해 지금의 것들을 응용해보자.

코드 >>


class cprint : public boost::static_visitor<>

{

public:

    template < typename T >

    void operator()(const T& t) const

    {

        std::cout << t;

    }

};

 

// for_each 

using var_t = boost::variant<int, double, std::string>;

 

std::vector<var_t> vars = {"hello", 1, 0.01};

 

std::for_each(vars.begin(), vars.end(), boost::apply_visitor(cprint())); // 모두 순회하며 콘솔에 출력한다.

반응형