![](/img/trans.png)
[英]Is the order for variadic template pack expansion defined in the standard?
[英]Order of function calls in variadic template expansion
我在開源項目中找到了基本上看起來像這樣的代碼:
template< typename... Args >
void expand_calls_hack(Args&&... args)
{}
template <unsigned int... Indices>
struct foo
{
static void bar(some_tuple_type& t)
{
meta::expand_calls_hack((std::get<Indices>(t).doSomething(), 0)...);
}
};
我認為這個“構造”用於為每個元組元素調用doSomething()
。 但是,在我看來,調用doSomething()
的順序是未定義的,至少它與C ++ 03中的普通函數一致。 這將是一個錯誤,因為調用有副作用。 我有兩個問題:
有什么用(tupleElement.doSomething(),0) - 是逗號運算符嗎? 我認為它與使用expand_calls_hack擴展調用有關。
如何解決這個問題,以便從左到右對呼叫進行評估? 請注意,我需要在VC2013上編譯。 我已經嘗試擴展lambda列表並按順序調用它,但我無法編譯。
我希望我沒有遺漏太多的上下文,但是對於好奇的,這段代碼的源代碼在github這里,第419行
問題的第一部分非常簡單: std::get<I>(t).doSomething()
可能返回void
。 因此,您無法直接將此表達式用作expand_calls_hack()
的參數。 即使doSomething()
返回void
使用逗號運算符也會安排參數出現。
調用可變參數函數模板時函數求值的順序並不特殊,即評估順序未定義。 然而,事實證明,使用大括號初始化定義為當一個構造器參數的計算順序(見,例如, 這個問題 )。 也就是說,您可以使用以下內容保證評估順序:
namespace meta {
struct order {
template <typename... T>
order(T&&...) {}
};
}
// ...
template <unsigned int... Indices>
struct foo
{
template <typename T>
static void bar(T&& t)
{
meta::expand_calls_hack((std::get<Indices>(t).doSomething(), 0)...);
meta::order{(std::get<Indices>(t).doSomething(), 0)...};
}
};
在上面的函數中,使用expand_calls_hack()
可以在我的系統上回溯表達式,而使用order
可以前后對它們進行評估。 我認為使用std::initializer_list<int>
可以實現類似的效果,這需要不需要可變參數模板:參數都是int
s:
namespace meta {
struct init_order {
init_order(std::initializer_list<int>) {}
};
}
它將與meta::order
完全相同。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.