簡體   English   中英

可變參數模板擴展中的函數調用順序

[英]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中的普通函數一致。 這將是一個錯誤,因為調用有副作用。 我有兩個問題:

  1. 有什么用(tupleElement.doSomething(),0) - 是逗號運算符嗎? 我認為它與使用expand_calls_hack擴展調用有關。

  2. 如何解決這個問題,以便從左到右對呼叫進行評估? 請注意,我需要在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM