2017-12-29 1 views
0

그래서 나는 그들이 printf에 전달되기 전에 형식 인수를 필터링 할 "소독제"기능을 구축을 위해 노력하고 있습니다. 제대로 포맷하기 위해 템플릿 전문성과 완벽한 전달

template<typename A> 
_CR_INLINE decltype(auto) sanitize_forward(A&& arg) { 
    return std::forward<A>(arg); 
} 

template<> 
_CR_INLINE decltype(auto) sanitize_forward<std::string>(std::string&& arg) { 
    return std::forward<const char*>(arg.c_str()); 
} 

은 그래서 모든 std::string이하는 const char*에 "붕괴"로되어있다.

template<typename...Args> 
_CR_INLINE void printf_safe(const std::string& format, Args&&...args) { 
    std::printf(format.c_str(), sanitize_forward<Args>(args)...); 
} 

나는 인수가 내가 std::forward을 반환 왜 완벽 printf- 전달 ,되고 싶어요. 그러나 이것이 구현되어야하는 방법에 대해 정말로 머리를 감쌀 수는 없습니다.

1) decltype(auto) 맞습니까? std::forward의 반환에 대한 r 값 참조를 유지해야합니다. 맞습니까? std::string&& 또는 std::string :

2) 어떻게 템플릿을 전문으로해야합니까?

3) 추론 해 전달 참조 오른쪽 실제 형태와 동일해야?

+1

당신은'printf'를 위해 앞으로 갈 필요가 없습니다. –

+0

하지만 printf가 내부 로깅 기능이라고 가정 해 봅시다. 어떻게 구현해야합니까? 또한 왜 필요하지 않은 인수를 전달하는 것이 정확히 무엇입니까? – mutex36

답변

2

그래서 형식화 인수가 printf으로 전달되기 전에 필터링하는 "새니 타이 저"함수를 작성하려고합니다.

귀하의 전제는 잘못된 것 같다. printfva_arg를 사용하는 C 함수 - 그것은 할 수 또는 완벽한 전달을 필요로하지 않는다.

http://en.cppreference.com/w/cpp/io/c/fprintf

은 또한 결코 인수를 "소비"하는 것,하지만 단지 그들로부터 읽습니다. 임시 및 비 임시 항목을 구별하는 것은 의미가 없습니다. printf 래퍼에 const Args&...을 가져 가면됩니다.


1) decltype(auto) 맞습니까? std::forward의 반환에 대한 r 값 참조를 유지해야합니다. 맞습니까?

std::forward

는 좌변을 참조 또는 r- 수치 참조를 반환하거나. decltype(auto) 실제로 보존됩니다.

std::string에 대한 전문화가 유용하지 않습니다. std::forward<const char*>은 항상 const char* &&을 반환합니다. std::string를 rvalue 참조에 대한 .c_str()를 반환, 매우 위험하고 잘못된 또한

template<> 
_CR_INLINE const char* sanitize_forward<std::string>(std::string&& arg) { 
    return arg.c_str(); 
} 

소리 :이 약의 문자열의 내부 버퍼에 대한 포인터를 복용하고 난 다른 생각하지 않습니다 만료됩니다. 여기서 const std::string&을 가져 가고 싶을 것입니다.std::string&& 또는 std::string :


2) 어떻게 템플릿을 전문으로해야합니까?

어떻게 호출 되나요? 명시 적으로 템플릿 인수를 제공하고 있습니까? 템플릿 인수는 항상 비 참조이 될지, 아니면 왼쪽 값 참조비 참조이 될 것입니까? 당신이 sanitize_forward<Args>을 가지고 있기 때문에, 당신은 아마 모두를 호출하려고 시도합니다

...

  • sanitize_forward<std::string&>

    • sanitize_forward<std::string>

    • ... 어쩌면 이력서 - 예선와 . "전문화"비즈니스를 다루는 추가 명시 적 std::decay_t<Args> 매개 변수를 제공 할 수 있습니다.


      3) 추론 해 전달 참조 오른쪽 실제 형태와 동일해야?

      당신이 의미하는 바가 확실하지 않습니다. 당신은 정교 할 수 있습니까?

    3

    전달 참조를 거의 완전히 오해합니다. 예상되는 것, 그들은 혼란 스럽다.

    그들을 이해하려면, 당신은 참조 무너 규칙을 이해해야 std::forward 자체 템플릿 인수 공제 규칙 T&&를 추론하고, 그들이 어떻게 적어도 어느 정도 함께 묶어.

    먼저 참조 축소. 이 차트 좀 봐 : X&&int&&입니다 다음, int입니다

    If  Then  Then 
    X is  X& is  X&& is 
    T  T&  T&& 
    T&  T&  T& 
    T const& T const& T const& 
    T&&  T&  T&& 
    

    X합니다. Xint& 인 경우 X&&int&입니다.

    다시 읽어보십시오. 다시. 한번 더. 두 가지 모두 적용될 경우 &&&보다 우승합니다.

    다음으로, 공제. 나는 여기서 거짓말을 할 것이지만 그들은 거짓말을 단순화하고있다. 당신이 X&&을 추론 템플릿에 Foo&를 전달하면

    , XFoo&하고 X&&Foo&입니다. 당신이 X&&을 추론 템플릿에 Foo&&를 전달하면

    , XFoo하고 X&&Foo&&입니다.

    다음으로, std::forward은 조건부 이동입니다. 참조 변수 X&& x의 경우 std::forward<X>(x)decltype(x)(x)이고 x은 선언 된 유형으로 변환됩니다. x이 rvalue 참조 인 경우 x을 rvalue 참조로 캐스팅합니다. 이는 x의 형식이 x이 rvalue reference 인 경우에도 이 아니고 X&&이 아니기 때문에 필요합니다. r 값은 참조 번호 ~의 rvalue이지만 자체는 r 값이 아닙니다.

    이제 코드를 수정하십시오.


    template<class T> 
    struct tag_t{constexpr tag_t(){}}; 
    template<class T> 
    constexpr tag_t<std::decay_t<T>> tag{}; 
    
    template<class T> 
    auto sanitizer(tag_t<T>){ 
        return [](auto&& t)->decltype(auto){ 
        return decltype(t)(t); 
        }; 
    } 
    template<class A> 
    decltype(auto) sanitize(A&& arg) { 
        return sanitizer(tag<A>)(std::forward<A>(arg)); 
    } 
    
    auto sanitizer(tag_t<std::string>) { 
        return [](std::string const& s){return s.c_str();}; 
    } 
    
    template<class...Ts> 
    void printf_safe(const std::string& format, Ts&&...ts) { 
        std::printf(format.c_str(), sanitize(std::forward<Ts>(ts))...); 
    } 
    

    나는 SRP (단일 책임의 원칙)에 따라 - 나는 살균에서 앞으로 분할합니다.

    그런 다음 실제로 어떤 위생 조치 (sanitizer)를 수행했는지 (sanitize)를 분할했습니다.

    이렇게하면 "우연히"우승하는 완벽한 전달없이 std::string santization code를 한 번 쓸 수 있습니다.

    제쳐두고, 배열 인수를 포인터가 아닌 것으로 취급하려는 경우 감퇴를 remove ref로 바꾸고 cv를 제거하십시오.

    당신은 tag_t의 네임 스페이스 또는 형식의 네임 스페이스에 우리가 (하지의 std 자연스럽게 비트)을 살균하는 하나에서 sanitizer 과부하를 작성하여 sanitize 기능을 확장 할 수 있습니다.

    관련 문제