2017-02-10 65 views
0

我有一個模板函數通過參數包遞歸。實質上,它意味着將something.Get<A,B,C>()映射到something.Get<A>().Get<B>().Get<C>()遞歸模板函數不能用Clang編譯?

這可以通過執行(摺疊低於滿獨立源)來實現

template <typename... Pack> class Struct { 
    std::tuple<Pack...> mTuple; 
    template <typename Type> auto &GetRef_internal() { 
    return std::get<first_true<std::is_same<Type, Pack>::value...>::value>(
     mTuple); 
    } 
public: 
    template <typename Current> Current &GetRef() { 
    return GetRef_internal<Current>(); 
    } 
    template <typename Current, typename... Next, 
      typename std::enable_if<sizeof...(Next) != 0>::type * = nullptr> 
    auto &GetRef() { 
    auto current = GetRef_internal<Current>(); 
    return current.GetRef<Next...>(); 
    } 
}; 

其中first_true返回其爲真,第一元素的索引。

這使用g ++編譯,看起來在MSVC上也使用online compiler。當使用鏗鏘聲++進行編譯時,我得到以下錯誤:

test.cxx:40:31: error: expected '(' for function-style cast or type construction 
    return current.GetRef<Next...>(); 
          ~~~~^ 
test.cxx:38:9: error: cannot deduce return type 'auto &' for function with no return statements 
    auto &GetRef() { 
     ^
test.cxx:48:12: note: in instantiation of function template specialization 'Struct<Struct<int, Struct<float, float> >, Struct<char>, int>::GetRef<Struct<int, Struct<float, float> >, Struct<float, float> , nullptr>' requested here 
      .GetRef<Struct<int, Struct<float, float>>, Struct<float, float>>(); 
     ^
2 errors generated. 

這是什麼原因造成的?

p.s.實際的「生產代碼」比這個例子看起來更有用,但是在這裏發佈的內容太多了。

============================================== ===========================

#include <tuple> 
#include <type_traits> 

// Template to check if condition holds true for all members of a parameter 
// pack. 
template <bool... b> struct BoolArray {}; 
template <bool... b> 
using all_true = std::is_same<BoolArray<b...>, BoolArray<(b, true)...>>; 

//helper type trait 
template <bool... b> struct first_true { 
    template < 
     unsigned index = 0, 
     typename std::enable_if<index<sizeof...(b)-1>::type * = 
            nullptr> static constexpr unsigned check() { 
    return std::get<index>(std::make_tuple(b...)) ? index : check<index + 1>(); 
    } 
    template <unsigned index = 0, 
      typename std::enable_if<index >= sizeof...(b)-1>::type * = nullptr> 
    static constexpr unsigned check() { 
    return std::get<index>(std::make_tuple(b...)) ? index : 0; 
    } 
    static constexpr unsigned value = first_true<b...>::check(); 
}; 

//The actual problem struct 
template <typename... Pack> class Struct { 
    std::tuple<Pack...> mTuple; 
    template <typename Type> auto &GetRef_internal() { 
    return std::get<first_true<std::is_same<Type, Pack>::value...>::value>(
     mTuple); 
    } 
public: 
    template <typename Current> Current &GetRef() { 
    return GetRef_internal<Current>(); 
    } 
    template <typename Current, typename... Next, 
      typename std::enable_if<sizeof...(Next) != 0>::type * = nullptr> 
    auto &GetRef() { 
    auto current = GetRef_internal<Current>(); 
    return current.GetRef<Next...>(); 
    } 
}; 

int main() { 
    // Define a random nested struct 
    Struct<Struct<int, Struct<float, float>>, Struct<char>, int> myStruct; 
    // Then retrieve one of the substructures to instantiate the template 
    auto substruct = 
     myStruct 
      .GetRef<Struct<int, Struct<float, float>>, Struct<float, float>>(); 
return 0; 
} 

回答

0

current.GetRef<Next...>是一個從屬名稱,所以你需要指定GetRef名模板使用template關鍵字:

return current.template GetRef<Next...>(); 

約依賴名稱的詳細信息,請參閱Where and why do I have to put the "template" and "typename" keywords?

+0

這工作!今天學到了新東西。只要它讓我接受這個答案。有趣的是,g ++甚至可以用pedantic來解決它。 –

+0

@CodingCat規範說如果你有「foo.bar <」,要知道「bar」是否是一個模板,它應該首先在「foo」的類中查找。如果在那裏找不到「酒吧」,應該在整個表達式中查找。但要知道它是否存在於對象的類中,它必須先等到周圍的模板被實例化。鏘顯然是這樣。 GCC不會,因此認爲它是一個模板。我認爲這也是https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55576中的問題。在那個bugreport中,GCC拒絕一個有效的程序。 –

+0

「模板」消歧器的全部用途是幫助編譯器確定名稱是否爲模板。但是GCC決定自己做,而不使用消歧器,因此在作爲成員的表達式上下文中找到「GetRef」。我不認爲這個GCC行爲是正確的。 –