2016-08-05 71 views
1

這是可能的:模板參數不fulfulling所有要求

struct A { 
    //void f(); < not declared in struct A 
}; 

template<typename T> 
struct Wrapper { 
    T t; 
    void call_f() { t.f(); } 
}; 

int main() { 
    Wrapper<A> w; 
} 

這編譯罰款,只要w.call_f()不叫。 w.call_f()無法實例化,因爲A::f不存在。

我在與被不同T類型,這並不總是實現接口部分全部採用這種包裝的模板的情況。 (主要是爲了避免代碼重複)。

這不起作用:

struct A { 
    //using i_type = int; < not declared/defined 
}; 

template<typename T> 
struct Wrapper { 
    using its_i_type = typename T::i_type; 
     // compile error, even if `i_type` gets never used 
}; 

int main() { 
    Wrapper<A> w; 
} 

沒有做到這一點:

struct A { 
    //using i_type = int; < not declared/defined 
}; 

template<typename T> 
struct Wrapper { 
    typename T::i_type call_f() { return 0; } 
     // does not compile, even if `call_f()` is never instantiated 
}; 

int main() { 
    Wrapper<A> w; 
} 

是否有處理這些情況的好方法,沒有大量重複的代碼(如專門爲Wrapper,等等。)?

回答

3

您可以推遲its_i_type的類型扣除。基本上,你創建一個簡單的包裝,你必須經歷。


將其擴展到您需要其他類型的,(我想建議type_traits樣的解決方案,但因爲你不想專業化),你可以定義所有你需要的類型:

template<typename T> 
struct Wrapper { 
private: 
    template<typename U> struct i_typper { using type = typename U::i_type; }; 
    template<typename U> struct k_typper { using type = typename U::k_type; }; 
    template<typename U> struct p_typper { using type = typename U::p_type; }; 
public: 
    using i_trait = i_typper<T>; 
    using k_trait = k_typper<T>; 
    using p_trait = p_typper<T>; 
}; 

實施例:

struct A { using i_type = int; }; 
struct B { using i_type = int; using k_type = float; }; 

int main() { 
    Wrapper<A> w; //Works now. 

    Wrapper<A>::i_trait::type mk1; //Works 
    Wrapper<A>::k_trait::type mk2; //Fails, not defined 
    Wrapper<B>::i_trait::type mk3; //Works 
    Wrapper<B>::k_trait::type mk4; //Works 
} 

對於的情況下:

template<typename T> 
struct Wrapper { 
    typename T::i_type call_f() { return 0; } 
     // does not compile, even if `call_f()` is never instantiated 
}; 

你這裏有幾個選項:

  1. 使該功能的成員函數模板
  2. 使用某種形式的type_traits機制,這仍然會涉及到專業化
  3. 去抽象共同Wrapper的方式東西在基類WrapperBase;

對於第一種選擇,你必須稍作修改,以進一步defer deduction

template<typename T> 
struct Wrapper { 
private: 
    template<typename U, typename> struct i_typper { using type = typename U::i_type; }; 
    template<typename U, typename> struct k_typper { using type = typename U::k_type; }; 
    template<typename U, typename> struct p_typper { using type = typename U::p_type; }; 
public: 
    using i_trait = i_typper<T, void>; 
    using k_trait = k_typper<T, void>; 
    using p_trait = p_typper<T, void>; 

    template<typename U = void> 
    typename k_typper<T, U>::type call_f() { return 0; } 
}; 

我將離開第二個選項作爲一個練習:(它可能最終被類似:

template<typename T> 
struct wrapper_traits { 
    .... 
}; 

template<> 
struct wrapper_traits<A>{ 
    using .... 
}; 

template<typename T> 
struct Wrapper { 
    .... 
public: 
    using i_trait = wrapper_traits<T>; 
    using k_trait = wrapper_traits<T>; 
    using p_trait = wrapper_traits<T>; 
}; 

Jarod's answer是簡單的,但這個,如果你沒有std::experimental訪問將工作,或者你的公司代碼策略禁止你...

+0

以及如何對一個'call_f'返回'i_type'? – aschepler

+0

@aschepler,那麼它會失敗。在這種情況下,我將使'call_f'成爲模板成員函數,或者我將使用'type_trait'類的解決方案,這將涉及專業化 – WhiZTiM

+0

*「您有兩個選項[..] 1. [.. ] 2。[..] 3。[..]「* :-)(我知道,多個編輯)。 – Jarod42

2

隨着std::experimental::is_detected,你可以做

template<typename T> 
using i_type_t = typename T::i_type; 

template<typename T> 
struct Wrapper { 
    using its_i_type = typename std::experimental::detected_t<i_type_t, T>; 
     // would be T::i_type or std::experimental::nonesuch 
}; 

還是要更好地處理案件,是這樣的:

template<typename T, bool = std::experimental::is_detected<i_type_t, T>::value> 
struct WrapperWithIType { 
    // Empty for false case. 
}; 

template<typename T> 
struct WrapperWithIType<T, true> { 
    using its_i_type = i_type_t<T>; 

    its_i_type call_f() { return 0; } 
}; 

然後

template<typename T> 
struct Wrapper : WrapperWithIType<T> { 
    // Common stuff 
}; 
+0

任何想法爲什麼'std :: is_detected'在C++ 17中不被接受? ... – WhiZTiM

+0

@WhiZTiM它在TS(技術規範,目前在g ++ - 6中工作)。 – TemplateRex