ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • boost::variant(std::variant c++17) 사용하기
    프로그래밍/c++ 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())); // 모두 순회하며 콘솔에 출력한다.

    반응형
Designed by Tistory.