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;
}
這工作!今天學到了新東西。只要它讓我接受這個答案。有趣的是,g ++甚至可以用pedantic來解決它。 –
@CodingCat規範說如果你有「foo.bar <」,要知道「bar」是否是一個模板,它應該首先在「foo」的類中查找。如果在那裏找不到「酒吧」,應該在整個表達式中查找。但要知道它是否存在於對象的類中,它必須先等到周圍的模板被實例化。鏘顯然是這樣。 GCC不會,因此認爲它是一個模板。我認爲這也是https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55576中的問題。在那個bugreport中,GCC拒絕一個有效的程序。 –
「模板」消歧器的全部用途是幫助編譯器確定名稱是否爲模板。但是GCC決定自己做,而不使用消歧器,因此在作爲成員的表達式上下文中找到「GetRef」。我不認爲這個GCC行爲是正確的。 –