2017-11-18 1 views
-2

필자는이 방법을 최소한으로 검증 할 수있는 방법을 찾기 위해 애를 썼지 만 어떻게해야하는지 생각할 수 없습니다. 나는 함께 추가하려고하는 두 가지 예상 유형이 있습니다. 예상되는 데이터 유형은 int, double 등일 수 있습니다. 예외 일 수 있습니다. 이론적으로 예외를 가진 데이터 유형을 추가 할 수 있어야하며 값을 물어 보면 프로그램을 정상적으로 실행할 수 있습니다. 프로그램을 중단하지 않고 예외를 반환해야합니다.템플릿 형식으로 C++ 연산자를 오버로드하면 오류가 발생합니다.

나는이 프로그램을 실행하려고 할 때마다 어디서부터 시작해야할지 모를 수백 줄의 오류 메시지를 볼 수 있는데, 하나의 오류는 no matching function for call to 'operator+(double&,double&)인지 알지 못한다. 2 개의 Expected를 함께 추가하려면 유형 자체를 추가하고 싶지 않습니다. 결국, 나는 Expected를 추가하고, 리턴되고 기대된다.

나는 정말로 여기에 갇혀있다, 내 apply 함수가 잘못 구현되었다는 말을 들었지만 솔직히 왜 그런지 알 수 없다. 내가 도대체 ​​뭘 잘못하고있는 겁니까?

#include <stdexcept> 
#include <exception> 
#include <functional> 
#include <variant> 

template<typename T> 
class Expected 
{ 

public: 
    Expected(T t) : state(t), valid(true){} 
    Expected(std::exception_ptr e) : state(e), valid(false){} 
    Expected(std::exception e) : state(std::make_exception_ptr(e)), valid(false){} 

    T value() const 
    { 
     if(valid) return std::get<T>(state); 
     std::rethrow_exception(std::get<std::exception_ptr>(state)); 
    } 

    bool isValid() 
    { 
     if(valid) return true; 
     return false; 
    } 

    template<typename U> 
    Expected<U> apply(std::function<U(T)> f) 
    { 
     if(!valid) return std::get<std::exception_ptr>(state); 
     try 
     { 
      return f(std::get<T>(state)); 
     } 
     catch(...) 
     { 
      return std::current_exception(); 
     } 
    } 
private: 

    std::variant<T, std::exception_ptr> state; 
    bool valid; 

}; 

template<typename T> 
std::ostream& operator<< (std::ostream& o, Expected<T> e) 
{ 
    try 
    { 
     o << e.value(); 
    } 
    catch(std::exception &a) 
    { 
     o << a.what(); 
    } 
    catch(...) 
    { 
     o << "Unexpected Error"; 
    } 

    return o; 
} 

template<typename T, typename V> 
auto operator+(Expected<T> t, Expected<V> v) 
{ 
    return t.apply([&](T myT){return operator+(myT,v);}); 
} 
template<typename T, typename V> 
auto operator+(Expected<T> t, V v) 
{ 
    return t.apply([&](T myT){return operator+(myT,v);}); 
} 
template<typename T, typename V> 
auto operator+(V v, Expected<T> t) 
{ 
    return t.apply([&](T myT){return operator+(v,myT);}); 
} 

int main() 
{ 
    Expected<int> a = 1; 
    Expected<int> b = 2; 

    std::cout << a + b << std::endl; 
} 
+0

'그건 : 당신이 원하는 무엇을, 거의 항상, 그 결과를 결정하기 위해 metafunction를 사용하여 다음 임의의 호출을 추론하고있다. 'variant :: which'를 호출하여 저장된 값의 타입의 인덱스를 얻을 수 있습니다. –

+0

유효한 @MaximEgorushkin? 'isValid()'또는 부울'valid? 이() == '0'state.which 같이 계산 될 수 있기 때문에 – Sailanarmo

+0

'valid' 데이터 부재는 불필요하다. –

답변

4

다음은 첫 번째 문제의 감소 예입니다. 운영자 만 전화 할 수 있습니다.게다가 연산자를 사용하는 것이 어쨌든 읽기 쉽습니다. 그렇게하십시오. +을 사용하십시오. (또한, 코드의 한 부분으로, 대신 아마도 operator+ 무엇을해야 op를 사용).

template <typename T> 
struct X { 
    template<typename U> 
    U apply(std::function<U(T)> f); 
}; 

int main() { 
    X<int>{}.apply([](int){return 2.0;}); // error 
} 
기본적으로

, std::function 거의 항상 잘못을 추론 :


다음은 두 번째 문제의 감소 예입니다. 이 람다 std::function<double(int)> 아니다하는 std::function 없습니다. valid` 여기에 꼭 필요한 것은

template <typename T> 
struct X { 
    template <typename F, typename U = std::invoke_result_t<F&, T>> 
    U apply(F f); 
}; 
+1

'예상 됨 '은 (는) 'U'가 아닙니다. 이 내 능력의 범위를 벗어나는 문제에 복용 내 처음으로 – Yakk

+0

좋아, 미안 해요 모든이의 정말 당황되고있다. 답변 해 주셔서 감사합니다. 람다가'std :: function'이 아니라고 말할 때 설명해 주시겠습니까? 나는 그 기능의 결과를 포착하려한다고 생각했다. – Sailanarmo

+0

@Sailanarmo 나는 그 말을 의미합니다. 람다는'std :: function'이 아닙니다. 올바른 매개 변수 유형의 경우 람다에서'std :: function'을 생성 할 수는 있지만 같은 것은 아닙니다. 'CONST의 char *가의''표준 :'을 basic_string 아니라, 당신이'표준 :'const를 숯불 *'에서'을 basic_string을 구성 할 수있는 같은 방법으로. – Barry

3

첫째 : 당신은 너무 많은 오류를 얻고있는 경우가 여전히 다수로보고 될 수있다 (코드에 한 가지 문제까지 될 때까지 일반적으로, 일부 코드를 떠나하여 테스트 케이스를 단순화 오류, 그래도). 그 오류를 이해할 것인가, 아니면 구체적으로 물어볼 것인가. 이 경우 이 아닌 operator +이라는 하나의 과부하로 시작하는 것입니다.


이제 코드에 여러 가지 문제가 있습니다. 먼저 대신에 operator+ (a, b)을 호출하는 이유는 무엇입니까? 실제로는 operator+ 함수에 두 개의 double이 사용되지 않으므로이 질문에서 명시 적으로 언급 한 오류가 발생합니다. 기본 제공 연산자 +은 함수가 아니기 때문에 호출 할 수 없습니다.

두 번째 문제는 람다 표현식의 타입 std::function 아니기 때문에 템플릿 파라미터 applyU는 람다 식으로부터 도출 될 수 있다는 것이다.

이 변경 operator +의 3 과부하에 일어날 필요가
return t.template apply<decltype(std::declval<T>() + v)>([&](T myT){return myT + v;}); 

(나는 3 과부하에 알 수없는 op 이상한 오타이며, 실제로도해야 가정 : 당신은 그것을 위해 명시 적 템플릿 인수를 제공해야 어떤 의미 호출 +).

apply 이전에 template 키워드가 필요하다는 점에 유의하십시오. 종속 컨텍스트에서 사용되기 때문입니다.

Barry's answerstd::function을 모두 제거하여 더 나은 방법을 제공합니다.

마지막으로 #include <iostream>이 누락되었습니다.

이 모든 변경 사항을 적용한 코드 [works].

int main() { 
    operator+(1, 2); // error 
} 

당신은 이름에 의해 운영 를 내장 호출 할 수 없습니다 :

+0

'apply'는 처음에는 std 함수를 사용하지 않아야합니다; 타입 소거 클래스 타입을 추론하면 코드 냄새가 나고 여기에 코드가 깨집니다. – Yakk

+0

@Yakk True true. 그러나 반환 형식에 쉽게 액세스 할 수 있습니다. 그래도 그 동안 게시 된 답변을 볼 수 있습니다. – Angew

+0

좋아요, 그럼이 모든 실수가 완전히 수정되었습니다. 그리고'operator +'에 대한 당신의 설명은 확실히 저를 도왔습니다. 'apply'가'std :: function'을 취하지 말아야하는 이유는 무엇입니까? 내가 당신의 코드를 사용한다면 그것이 그 것처럼 잘된 것처럼 보입니다. – Sailanarmo

관련 문제