2016-07-29 123 views
2

我有一個模板結構SFoo包含的成員結構SZugC++:部分專業模板的類型參數作爲另一個模板類的成員類型

template <typename tTYPE> 
struct SFoo 
    { 
    struct SZug {}; 
    }; 

我有另一種結構SBar,需要一個類型參數:

template <typename tTYPE> 
struct SBar 
    { /* stuff */ }; 

我想使用SZug爲類型參數專門SBar,像這樣:

template <typename tTYPE> 
struct SBar<typename SFoo<tTYPE>::SZug> 
    { /* different stuff */ }; 

這不會編譯 - LLVM輸出:

非抵扣模板參數「TTYPE」

雖然編譯器可以很容易地推斷出這一點,如果它願意,我猜這是隻是C++規範需要專門涵蓋這種情況。

有什麼辦法可以達到這個目的嗎?
(注:我目前工作圍繞它通過移動SZugSFoo和使用using聲明,但它的醜陋)

+0

你打算做什麼之後?我不清楚你期望「專業化」做什麼。你能告訴我們你將如何聲明一個非專業化和專業化的SBar變量嗎? – Holt

+0

我實際上將這些純粹用作特徵類型,所以它們從未實際實例化過。 Bar簡單地爲另一個(未提及的)類提供一個constexpr成員指針(以及其他一些東西)。通常情況下,成員指針需要明確指定,但對於「SZug」專業化可以確定。 - (最終這與從1到N通用容器生成N對N通用嵌入容器有關 - 成員指針指向用戶的容器或節點信息「嵌入」(即成員變量)類型)。 – xaxazak

+0

我可以稍微修改一下'SZug'來檢測它,用SFINAE做你想做的事很容易(見我的答案)。如果你不能,我不確定是否有辦法檢測到'tTYPE'是'SFoo :: SZug'類。 – Holt

回答

2

我不知道我完全理解你想做的事,但你可以嘗試以下的(只需要添加特定的屬性SZug

template <typename tTYPE> 
struct SFoo { 
    struct SZug { 
     // Add this to be able to obtain SFoo<T> from SFoo<T>::SZug 
     using type = tTYPE; 
    }; 
}; 

再小的模板來檢查,如果一個類型是SFoo<T>::SZug

template <typename tTYPE, typename Enabler = void> 
struct is_SZug: public std::false_type { }; 

template <typename tTYPE> 
struct is_SZug<tTYPE, typename std::enable_if< 
    std::is_same<tTYPE, typename SFoo<typename tTYPE::type>::SZug>{} 
>::type>: public std::true_type { }; 

和輕微修改的SBar模板,使「專業化」,如果該類型是SZug

template <typename tTYPE, typename Enabler = void> 
struct SBar 
    { static void g(); }; 

template <typename tTYPE> 
struct SBar<tTYPE, typename std::enable_if<is_SZug<tTYPE>{}>::type> 
    { static void f(); }; 

小檢查:

void f() { 
    SBar<int>::g(); 
    SBar<SFoo<int>::SZug>::f(); 
} 

注:您也可以直接設置SFoo<T>type屬性在SFoo<T>::SZug,你只需要改變的std::is_same一點點的第二個參數。

+0

是的,這確實解決了問題,tyvm。對於我目前的問題,添加'using type = tTYPE;'非常簡單。 'SBar'上的額外參數更煩人,但仍然可以。我目前正在確定這是否比我目前的修復更加整潔。 - 如果明天沒有更好的答案,我會打勾解決。乾杯。 – xaxazak

+0

@xaxazak這是一個常用的習慣用法,將這樣的'Enabler'參數添加到模板中(大多數情況下應該自動推導出這個參數),但如果您需要使用'SBar'作爲模板模板參數,則可能會出現問題。也許如果你能詳細說明爲什麼它很煩人,我可能會提出一個更合適的解決方案? – Holt

+0

主要是模塊化。 SBar已經被頻繁使用(在1到N容器中),並且不需要知道這個新功能(N到N個容器)。但它是我自己的代碼,所以我可以更新它,並且它不用於任何地方的模板模板內容(儘管'SZug'使用模板參數)。 – xaxazak

1

你可以得到效果爲您正在尋找通過以下(打印出0 1,順便說一句):

#include <type_traits> 
#include <iostream> 

namespace detail 
{ 
    struct SZugBase{}; 
} 

template <typename tTYPE> 
struct SFoo                                 
{ 
    struct SZug : public detail::SZugBase {}; 
}; 

template<typename tType, bool IsFoo> 
struct SBarBase 
{ 
    int value = 0; 
}; 

template<typename tType> 
struct SBarBase<tType, true> 
{ 
    int value = 1; 
}; 

template <typename tTYPE> 
struct SBar : public SBarBase<tTYPE, std::is_convertible<tTYPE, detail::SZugBase>::value> 
{ /* stuff */ }; 

int main() 
{ 
    SBar<int> b0; 
    SBar<SFoo<int>::SZug> b1; 

    std::cout << b0.value << " " << b1.value << std::endl; 
} 

說明

首先,我們得到一個SZug常規b類ASE:

namespace detail 
{ 
    struct SZugBase{}; 
} 

template <typename tTYPE> 
struct SFoo            
{ 
    struct SZug : public detail::SZugBase {}; 
}; 

注意以下幾點:

  1. SZugBase不受任何參數,所以很容易獨立地指的SFoo

  2. SZugBase參數來它是在一個detail命名空間,所以,按照常見的C++約定,你告訴客戶端你的代碼忽略它。

現在我們給SBar兩個基類,專業上的東西是否可以轉換爲的SZug非模板的基礎:

template<typename tType, bool IsFoo> 
struct SBarBase 
{ 
    int value = 0; 
}; 

template<typename tType> 
struct SBarBase<tType, true> 
{ 
    int value = 1; 
}; 

最後,我們只需要做出SBar這些基地的子類(取決於專業化):

template <typename tTYPE> 
struct SBar : public SBarBase<tTYPE, std::is_convertible<tTYPE, detail::SZugBase>::value> 
{ /* stuff */ }; 

請注意,你不擅長SBar她e,你更專門化基類。不過,這實際上會產生相同的效果。

+0

適用於'SBar > b1;'。不幸的是,我正在尋找'SBar ::'**'SZug' **'> b1;'(AFAICT仍然會打印0)。 – xaxazak

+0

@xaxazak你是對的 - 我錯過了這個問題的細節,但這個原則適用。答案細節的一些細微變化適用於您的原意。要點如下:1.非模板「細節」基礎,2.根據是否可以轉換爲基礎來專門設計基類。 –

+0

是的,這確實解決了這個問題。我正在越過我的手指可能會有一個更整潔的方式來做到這一點。你的解決方案和Holt的都可以被接受,但恕我直言,我認爲增加一個修補程序成員類型(Holt的方法)比從修復程序結構繼承更好。 – xaxazak