2010-09-22 181 views
1

我試圖做一個函數模板,它將接受兩個(或更多)下面列出的嵌套可變參數類模板作爲參數,並將它們放入另一個數據結構中將接受不同的類型(對或元組是我最有可能使用的)。這裏有類別和亞類,與我的函數的使用沿(函數定義遠低於):接受嵌套可變參數類模板作爲函數模板的參數

template<typename... Args> struct Entity { 

    template<typename... InnerEntArgs> struct InnerEntity { 
     InnerEntity(InnerEntArgs... inner_ent_args) { 
      ... //do stuff w/ InnerEntArgs pack 
      ... //do stuff that makes Inner dependent on Outer's Args pack 
     } 
    }; 
}; 

struct ThingA : Entity<int, string> { 
    ... //construct ThingA 
}; 

struct ThingB : Entity<string, string> { 
    ... //construct ThingB 
}; 

auto foo = my_func(
    ThingA::InnerEntity<int, int, int>(1, 2, 3) 
    , ThingB::InnerEntity<string, int>("bar", 1) 
); 

下面是我拼湊起來的功能的代碼,它編譯罰款,但我米不知道它是否設置正確。具體地講,我對如何typename::template有點模糊正在編譯器在這種背景下高興,如果此功能行爲的方式我很期待:

template< 
    typename... ArgsA, typename... ArgsAInner 
    , typename... ArgsB, typename... ArgsBInner 
> auto my_func(
    typename Entity<ArgsA...>::template InnerEntity<ArgsAInner...> A 
    , typename Entity<ArgsB...>::template InnerEntity<ArgsBInner...> B 
) -> tuple<decltype(A), decltype(B)> { 
    return make_tuple(A, B); 
} 

認爲我有一個好掌握如何推導/推斷參數包,以及auto,decltype和尾隨返回類型是如何做的,但如果我錯了,請告訴我如何。另外,如果有人關心展示這個函數的可變參數版本,它可以接受任意數量的嵌套variadic類模板,並將它們放入合適的容器或數據結構中,那將很棒,但我主要是關注完全瞭解typename::template。提前致謝! *如果我錯誤地使用了這個標題,或者我混淆了術語,請解釋一下。 :)我在這裏學習。

回答

4

這不起作用,因爲Entity<Args>::InnerEntity是一個非推導的上下文。意味着ArgsA...ArgsAInner...不能被推斷,對於其他參數也是如此。這是因爲在編譯器推導出Args之前,它必須知道InnerEntity是什麼類型的成員,但要知道,它必須推導出Args

您可以將此功能作爲朋友功能模板插入到Entity<Args...>中,只要它們都是同一個模板的成員就可以使用。但上次我檢查,GCC沒有找到類模板中定義的朋友函數。

template<typename ...Args> 
class Entity { 
    template<typename ...ArgsInner> 
    class InnerEntity { 

    }; 

    template<typename ...ArgsAInner, typename... ArgsBInner> 
    > friend auto my_func(
     InnerEntity<ArgsAInner...> A 
     , InnerEntity<ArgsBInner...> B 
) -> tuple<decltype(A), decltype(B)> { 
     return make_tuple(A, B); 
    } 

}; 

你也可以聲明一些成員的typedef在InnerEntity指定外部類的類型,並在這方面制定my_func,使SFINAE可以整理出來給非會員。

template<typename ...Args> 
class Entity { 
    template<typename ...ArgsInner> 
    class InnerEntity { 
    typedef Entity outer_entity; 
    };  
}; 

template<typename A, typename B, typename Result> 
struct require_entity { }; 

template<typename ...ArgsA, typename ...ArgsB, typename Result> 
struct require_entity<Entity<ArgsA...>, Entity<ArgsB...>> { 
    typedef Result type; 
}; 

template<template<typename...> class AInner, template<typename...> class BInner, 
     typename ...ArgsAInner, typename ...ArgsBInner> 
> auto my_func(
     AInner<ArgsAInner...> A 
    , BInner<ArgsBInner...> B 
) -> typename require_entity< 
     typename AInner<ArgsAInner...>::outer_entity, 
     typename BInner<ArgsBInner...>::outer_entity, 
      tuple<decltype(A), decltype(B)>>::type 
{ 
    return make_tuple(A, B); 
} 

當然你不需要那麼template<typename...> class AInner的事情,如果你不需要訪問ArgsAInner類型,如在上述my_func。在這種情況下,您最好接受typename AInner,而且寫得更少。 SFINAE仍然會確保只有正確的東西被接受。

+0

我明白了。也許我會在這裏留下相關的信息,但我仍然有點困惑,爲什麼上述不起作用。實體有一些定義Args的子類,它有一個用於創建InnerEntity對象的成員函數,並且該成員函數接受並作爲一個包傳遞InnerEntity的參數。鑑於此,編譯器是否應該能夠推導出各種Args包,因爲它們在編譯時都是已知的? – 2010-09-22 20:11:59

+1

@pheadbaq實體可以專用於某些參數,使得InnerEntity與其他參數完全不同。一般來說,如果你有'typename T :: foo',那麼一個函數模板函數參數,那麼'T'不能被該參數推導出來。 – 2010-09-22 20:18:42

+0

在我的答案和我自己的代碼上多加咀嚼之後,我認爲朋友解決方案畢竟不會起作用,因爲ThingA和ThingB(請參閱我的編輯代碼)不會從同一實體模板繼承。看起來像typename AInner + SFINAE可以很好地工作。謝謝! – 2010-09-22 22:02:30