2016-06-06 2 views
0

나는 잠시 동안 boost::variant을 이미 사용하고 있습니다. 그러나 여전히 의문의 여지가 남아 있습니다. 나는 std::pair<int, int>boost::variant A를 저장하려고 해요로 다음 코드는 컴파일되지타입이 boost :: variant에 저장 될 수있는지를 추론하십시오.

, 그에만 int, doublestd::string를 포함 할 수 있습니다. 여전히 convert 함수가 필요하지만 적합하지 않게 형식을 boost::variant에 저장하려고 할 때 예외가 발생합니다.

#include <iostream> 
#include <boost/variant.hpp> 
#include <vector> 

typedef boost::variant<int, double, std::string> TVar; 

template<typename T> 
std::vector<TVar> convert(const std::vector<T>& vec) { 
    std::vector<TVar> ret; 
    for (size_t t = 0; t < vec.size(); t++) { 
     ret.push_back(vec[t]); 
    } 
    return ret; 
} 

int main(int arg, char** args) { 
    { 
     std::vector<double> v = { 3,6,4,3 }; 
     auto ret=convert(v); 
     std::cout << ret.size() << std::endl; 
    } 
    { 
     std::vector<bool> v = { true, false, true }; 
     auto ret=convert(v); 
     std::cout << ret.size() << std::endl; 
    } 
    { 
     std::vector<std::pair<int, int>> v = { std::make_pair<int, int>(5,4) }; 
     auto ret = convert(v); 
     std::cout << ret.size() << std::endl; 
    } 
    return 0; 
} 

것 같다, 그 std::enable_if 솔루션의 일부가 될 수도 있지만, 나는 끝이를 가져올 수 없습니다. 나는 std::pair<int, int>boost::variant A를 저장하려고 해요로 다음 코드는 컴파일되지

답변

1

SFINAE를 사용한 나의 접근 방식입니다. 그것은 당신이 테스트를 추가 할 때마다 변경해야하기 때문에/TVar에서 유형을 제거하지만, 작동, 최선의 해결책이 아니다 :

//Using SFINAE to check if type can be converted into TVar 
template<typename T, typename = std::enable_if_t<std::is_same<TVar::types::item, T>::value 
    || std::is_same<TVar::types::next::item, T>::value 
    || std::is_same<TVar::types::next::next::item, T>::value>> 
std::vector<TVar> convert(const std::vector<T>& vec) { 
    std::vector<TVar> ret; 
    for (size_t t = 0; t < vec.size(); t++) { 
     ret.push_back(vec[t]); 
    } 
    return ret; 
} 

std::vector<std::nullptr_t> convert(...) 
{ 
    //throw Something 
    return{}; 
} 

리틀 설명 :

boost::variant라는 내부 형을 가지고 types. 이것은 기본적으로 컴파일 타임 링크 된 목록으로, 각 요소의 유형은 type입니다.

std::enable_if_t의 조건은 위의 조건 중 하나가 boost::variant의 유형이 될 것이다, true 경우

std::is_same<TVar::types::item, T>::value /*is T same as the first type in variant? */ 
|| std::is_same<TVar::types::next::item, T>::value /* is T same as second type */ 
|| std::is_same<TVar::types::next::next::item, T>::value /* is T same as third type */ 

그래서, 템플릿 convert은 촬영이다.

+0

안녕하세요. 이 멋진 솔루션을 찾아 주셔서 감사드립니다. 불행히도, 그것은 나를 위해 올바른 행동을하지 못했습니다. 나는 항상'convert (...)'함수의 두 번째 부분에 빠져있다. 프로그램은 '0'을 세 번 출력합니다. – Aleph0

+0

@FrankSimon 죄송합니다,이 버그를 눈치 채지 못했습니다 :) 이제는 작동하지만보기에는 좋지 않습니다 ... – Rakete1111

+0

와우. 그게 정말 저에게 기운이납니다. 불행히도, MSVC 2015와 컴파일되지 않습니다? 그것은 :'오류 C2275 : "TVar": 표현식으로 형식의 사용이 잘못되었습니다 .' 어떤 생각이 들었습니까? – Aleph0

4

, 그에만 int, doublestd::string를 포함 할 수 있습니다. 여전히 변환 할 함수가 필요하지만 적합하지 않게 형식을 boost::variant에 저장하려고 할 때 예외가 발생합니다.

이것은 실제로 당신이 원하는 것이 아니며, 당신이 갖고있는 행동에 더 행복해야합니다.

형식이 적합하지 않은 boost::variant의 형식을 저장하려고하면 프로그램에서 컴파일 타임에 명백한 문제 일 수 있습니다. 컴파일러는 진행 방법을 모릅니다 이 작업을 위해 문자 그대로 합리적인 코드를 사용할 수는 없습니다. 그것은 당신이 저장하려고하는 타입을 알고 있고, 당신이 가지고있는 변형의 종류를 알고 있고, 변환이 없다는 것을 알 수 있습니다.

컴파일러가 코드를 거부하고 변환이 없다고 말하면 문제에 대해 알게되는 즉시 문제에 대해 알려줍니다.

변환을 시도 할 때마다 런타임에 예외가 발생하는 경우에만 나중에 테스트 할 때까지 문제를 발견 할 수 없습니다. 이것은 훨씬 성가시고 비싸다. 컴파일러가 나쁜 변환 문제를 알고 있거나 알고 있어야 했음에 틀림 없다는 뜻이다.

일반적으로 C++에서 프로그래머는 일반적인 실수가 런타임 오류가 아닌 컴파일 타임 오류로 표시되도록 코드를 작성하려고합니다. boost::variant이이 아이디어를 염두에두고 작성되었습니다.

그래서 나는이 질문의 전제를 다시 살펴보고 그것이 실제로 무엇을 하려는지 설명하려고 노력해야한다고 생각합니다.

+0

사실 예외를 던지려는 아이디어는 가능한 한 작게 유지하는 예제 코드에만 해당됩니다. 제 경우에는 코드 중복을 피하기 위해 다른 유형으로 다른 유형을 처리해야합니다. 'T'는 통일 된 방식으로 처리 될 수있는'int','std :: string' 또는'double'과 같은 간단한 데이터 유형이 될 수 있습니다. 'T'가'Matrix' 나'Quaternion' 같은 복잡한 데이터 타입이라면 복잡한 데이터 타입마다 특별한 것을해야합니다. – Aleph0

+0

@ 프랑크 시몬 : 알겠습니다. 그래서 하나의 대체 접근법 (하나의 변형에있는 각 유형에 대해'std :: is_same'을 한 번 사용하고 or을 취하면 다른 방법으로'std :: is_constructible'을 시도해 볼 수 있습니다. . 단점은 몇몇 종류의 변환이 허용되므로이 테스트는 다른 테스트보다 훨씬 느릴 것입니다. 그러나 그것은 좋은 일이 될 수 있습니다. 구현하기가 훨씬 쉽습니다. HTH –