最近我發現了這個關于用模板展開回圈的StackOverflow 答案。答案指出“這個想法適用于 C 11”,我最終得到了這個:
namespace tmpl {
namespace details {
template<class T, T... values>
class integer_sequence {
public:
static constexpr size_t size() { return sizeof...(values); }
};
template<class T, class N, class... Is>
struct make_integer_sequence_helper :
make_integer_sequence_helper<T, std::integral_constant<T, N::value - 1>, std::integral_constant<T, N::value - 1>, Is...> {};
template<class T, class... Is>
struct make_integer_sequence_helper<T, std::integral_constant<T, 0>, Is...> {
using type = integer_sequence<T, Is::value...>;
};
template<class T, T N>
using make_integer_sequence = typename make_integer_sequence_helper<T, std::integral_constant<T, N>>::type;
template<class... Ts>
void variadic_noop(Ts... params) {}
template<class F, class T>
int call_and_return_0(F&& f, T i) {f(i); return 0;}
template<class T, T... Is, class F>
void loop(integer_sequence<T, Is...>, F&& f) {
variadic_noop(call_and_return_0(f, Is)...);
}
}
template<class T, T max, class F>
void loop(F&& f) {
details::loop(details::make_integer_sequence<T, max>{}, f);
}
}
讓我們舉一個簡單的例子來說明如何使用這個模板:
tmpl::loop<size_t, 20>([&](size_t idx) {
cout << "Loop " << idx << std::endl;
});
當我使用另一個答案中的 C 17 代碼時,它從 0 迭代到 19。但是,我撰寫的 C 11 jank 從 19 迭代到 0。
理論上,當details::loop()擴展時它應該變成這樣:
variadic_noop(call_and_return_0(f, 0), call_and_return_0(f, 1), call_and_return_0(f, 2), ...);
那么,如果 C call_and_return_0(f, 19)是 的最后一個引數,為什么它首先運行variadic_noop()?
uj5u.com熱心網友回復:
函式呼叫中函式引數的計算可以是從左到右、從右到左或任何其他順序,這些順序不需要是可預測的。
但是,當您有一個形式為子運算式, , ...,由逗號運算子分隔的單個運算式時,子運算式將始終按從左到右的順序計算,因為逗號運算子保證其左運算元在其右運算元之前進行評估。(在 C 17 之前,此保證僅適用于內置逗號運算子,不適用于任何多載運算子。)e_1, e_2, ..., e_ne_1e_2e_n
盡管函式呼叫也使用逗號,但函式呼叫中的逗號不強制執行從左到右的計算。鏈接答案中的代碼使用 C 17 折疊運算式來創建由逗號運算子分隔的運算式序列。
uj5u.com熱心網友回復:
補充一下 Brian 所說的,可靠地獲得訂單的唯一方法是將回圈撰寫為遞回模板。示例實作:
template <class T, T I, T... Is, class F>
void loop(integer_sequence<T, I, Is...>, F&& f) {
f(I);
loop(integer_sequence<T, Is...> {}, f);
}
template<class T, class F>
void loop(integer_sequence<T>, F&& f) {}
編輯:我再次查看了包擴展發生的位置,以及這個 StackOverflow 答案。為了避免函式求值順序問題,您可以使用花括號初始化器串列,以保證從左到右的順序。它還將允許更大的序列,因為不再需要遞回來展開回圈。
inline void init_list_noop(std::initializer_list<int>) {}
template<class T, T val, class F>
int call_and_return_0(F&& f) {
f(val);
return 0;
}
template<class T, T... vals, class F>
void loop(integer_sequence<T, vals...>, F&& f) {
init_list_noop({call_and_return_0<T, vals>(f)...});
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/348115.html
上一篇:使用FOR回圈遍歷JSON物件
