2016-09-09 1 views
3

상태가 숫자 (using state_t = unsigned)이고 번호가 (using transition_t = unsigned) 인 자동 데이터를 나타내는 클래스가 있다고 해봅시다. 물론 어떤 점에서는 transition_tstate_t이 같은 유형이기 때문에 컴파일러가 (의미 론적) 유형 안전을 시행하지 않기 때문에 일부 호출이 엉망이됩니다. 태그 (struct transition_tag {}; struct state_tag {};)로 템플릿 화 된 작은 클래스를 사용하여 쉽게 해결할 수 있으므로 이제 transition_tstate_t은 호환되지 않습니다. (최단 경로) 전신 전이로의 이행에서컴파일러가 적용한 의미 유형

  • predecessors_t지도 :

    /// Lightweight state/transition handle (or index). 
    template <typename Tag> 
    struct index_t_impl 
    { 
        using index_t = unsigned; 
    
        constexpr index_t_impl(index_t i) 
        : s{i} 
        {} 
    
        // Disallow index1_t i{index2_t{42}}; 
        template <typename T> 
        index_t_impl(index_t_impl<T> t) = delete; 
    
        bool operator==(index_t_impl t) const 
        { 
        return s == t.s; 
        } 
    
        // Disallow index1_t{42} == index2_t{42}; 
        template <typename T> 
        bool operator==(index_t_impl<T> t) const = delete; 
    
        /// Default ctor to please containers. 
        index_t_impl() = default; 
        constexpr operator index_t() const { return s; } 
        /// Be compliant with Boost integer ranges. 
        index_t_impl& operator++() { ++s; return *this; } 
        /// Be compliant with Boost integer ranges. 
        index_t_impl& operator--() { --s; return *this; } 
    
    private: 
        index_t s; 
    }; 
    

    는 또한, 난 아주 많이 비슷 두 구조를 가지고있다. 효율성을 위해 std::vector<transition_t>입니다.

  • path_t은 전환 색인 목록입니다. 효율성을 위해 std::vector<transition_t>입니다.

두 번째 완전히 다른 목적으로 std::vector<transition_t>을 사용하는이 문제가 있습니다. 물론, 태그로 템플릿 화 된 래퍼를 다시 소개 할 수는 있지만, 다시는 더러워집니다. 공개 상속은 매우 유혹적입니다 (Thou shalt not inherit from std::vector)!

하지만 실제로 기본 유형과 완전히 다르지만 호환되지 않는 새로운 유형을 도입 할 때마다 애드혹 솔루션에 지쳐 있습니다. 이와 관련하여 권고 사항이 있습니까? 공개 상속은 정말 매력적이지만 추가 인스턴스에 톤이 부풀어 오르는 코드를 도입하지 않을까요? 아마도 Crashworks (https://stackoverflow.com/a/4353276/1353549)에서 권장하는 공개 구성 (struct predecessors_t { std::vector<transition_t> v; };)이 더 나은 확장 옵션일까요?

미래에 C++의 새로운 점이 있습니까?

+2

나는 그것이 표준에 들어오는 모르는 그러나 당신은 여기에서 볼 수 있습니다 : HTTP : // 유래.co.kr/questions/28916627/strong-typedefs – Hayt

답변

6

상황에 따라 다른 출처 (값이 모두 같은 유형 (예 : int)이지만 의미 상으로는 시스템을 조정하는 모든 종류의 상황에서 컴파일러 적용 의미 유형을 가져 오는 문제가 발생할 수 있습니다. (x, y, z = 0,0,0)의 오프셋을 나타 내기 때문에 유형을 혼합해서는 안됩니다. 수학에서 자주 발생합니다. 양수 x 및 y로 사분면을 그릴 때 원점 왼쪽 아래에 있고, 컴퓨터 과학은 우주선 탐색에 원점 왼쪽 위를 놓는 것이 매우 일반적입니다. 2012 년

는, 비얀 스트로브 스트 룹은 그가 C++ 11 사용하여 템플릿, 사용자 정의 리터럴 도입 컴파일러 강화 된 의미 유형 안전 유형이 풍부한 프로그래밍라는 것에 흥미있는 이야기, 청구 된 없이 실행 시간을 준 오버 헤드 구현 및 화성 기후 관찰자 snafu (350M 우주선 + 임무는 의미 론적 유형 안전성의 부재로 인해 손실 됨)에서 배운 교훈까지도 포함합니다. 여기서 의미 론적 유형을 다루는 부분을 볼 수 있습니다 : https://youtu.be/0iWb_qi2-uI?t=19m6s

Stroustrup의 데모 코드를 기반으로 샘플 코드를 발췌하고 현재 표준과 필요한 연산자 오버로드가 구현 된 부분을 작성했습니다. Bjarne의 예제와 달리이 컴파일은 실제로 컴파일됩니다.)이 코드의

요점은 여기에서 찾을 수 있습니다 : https://gist.github.com/u-007d/361221df5f8c7f3466f0f09dc96fb1ba

//Compiled with clang -std=c++14 -Weverything -Wno-c++98-compat main.cpp -o main 

#include <iostream> 
#include <string> 

template<int M, int K, int S> //Meters, Kilograms, Seconds (MKS) 
struct Unit 
{ 
    enum { m=M, kg=K, s=S }; 
}; 

template<typename Unit> //a magnitude with a unit 
struct Value 
{ 
    double val; //the magnitude 
    constexpr explicit Value(double d) : val(d) {} //construct a Value from a double 
}; 

//Basic Semantic Units for MKS domain 
using Meter = Unit<1, 0, 0>; 
using Kilogram = Unit<0, 1, 0>; 
using Second = Unit<0, 0, 1>; 
using Second2 = Unit<0, 0, 2>; 

//Semantic Value Types for MKS domain 
using Time = Value<Second>; 
using Distance = Value<Meter>; 
using Mass = Value<Kilogram>; 
using Speed = Value<Unit<1, 0, -1>>; //Speed is meters/second 
using Acceleration = Value<Unit<1, 0, -2>>; //Acceleration is meters/second^2 

//Operator overloads to properly calculate units (incomplete; for demo purposes) 
Speed operator/(const Distance& lhs, const Time& rhs) 
{ 
    return Speed(lhs.val/rhs.val); 
} 

Acceleration operator/(const Speed& lhs, const Time& rhs) 
{ 
    return Acceleration(lhs.val/rhs.val); 
} 

//Define literals 
constexpr Distance operator"" _m(long double ld) 
{ 
    return Distance(static_cast<double>(ld)); 
} 

constexpr Mass operator"" _kg(long double ld) 
{ 
    return Mass(static_cast<double>(ld)); 
} 

constexpr Time operator"" _s(long double ld) 
{ 
    return Time(static_cast<double>(ld)); 
} 

constexpr Acceleration operator"" _s2(long double ld) 
{ 
    return Acceleration(static_cast<double>(ld)); 
} 

int main() 
{ 
    Speed sp = Distance(100)/Time(9.58); //Not bad, but units could be more convenient... 
    Distance d1 = 100.0_m; //A good distance to run a race 
    Speed sp1 = 100.0_m/9.58_s; //A human can run this fast 
// Speed sp2 = 100.0_m/9.8_s2; //Error: speed is m/s, not m/s^2 
// Speed sp3 = 100.0/9.8_s; //Error: 100 has no unit 
    Acceleration ac1 = sp1/0.5_s; //Faster than any human 

    return EXIT_SUCCESS; 
} 
+1

니스. 사소한 문제 :'sp3'에 대해서, 나는'_m' 부분이 없다고 생각합니다. –

+0

감사합니다. 예이츠켈. 결정된. – U007D