2013-04-15 20 views
4

在可變參數模板中,...運算符將參數包擴展爲一系列以逗號分隔的參數(以最簡單的形式)。我的問題是:如何調用some_function()多個參數逗號分隔的作品,並用...運算符調用它不?C++ 11可變參數模板和逗號分隔表達式等效

我談論這個代碼:

template<typename... Args> inline void expand(Args&&... args) 
{ 
    some_function(22),some_function(32); // Works 
    some_function(args)...; // Doesn't work - ERROR 
} 

不應該這兩條線產生類似的輸出?

+1

小心發佈錯誤? –

+0

編譯完成時出錯: source.cpp:函數'void expand(Args && ...)': source.cpp:18:23:error:expected';'在'...'標記之前 some_function(args)...; //不起作用 - 錯誤 – Paul

回答

5

因爲在第一種情況下,您沒有用逗號分隔的參數,而是使用逗號運算符,這是一個完全不同的野獸。

您可以實現的功能expand遞歸:

inline void expand() {} 

template<typename T, typename... Args> 
inline void expand(T&& head, Args&&... tail) 
{ 
    some_function(head); 
    expand(tail...); 
} 
+3

另一種解決方案是將其擴展到括號​​括起來的初始化列表中。即'expand foo {args ...};' – Pubby

1

鈍的回答是,這只是不是一個上下文,其中標準允許包擴展。允許範圍內的完整列表在14.5.3/4規定:

4 A pack expansion consists of a pattern and an ellipsis, the instantiation of which produces zero or more instantiations of the pattern in a list (described below). The form of the pattern depends on the context in which the expansion occurs. Pack expansions can occur in the following contexts:

— In a function parameter pack (8.3.5); the pattern is the parameter-declaration without the ellipsis.

— In a template parameter pack that is a pack expansion (14.1):

  • if the template parameter pack is a parameter-declaration; the pattern is the parameter-declaration without the ellipsis;

  • if the template parameter pack is a type-parameter with a template-parameter-list; the pattern is the corresponding type-parameter without the ellipsis.

— In an initializer-list (8.5); the pattern is an initializer-clause.

— In a base-specifier-list (Clause 10); the pattern is a base-specifier.

— In a mem-initializer-list (12.6.2); the pattern is a mem-initializer.

— In a template-argument-list (14.3); the pattern is a template-argument.

— In a dynamic-exception-specification (15.4); the pattern is a type-id.

— In an attribute-list (7.6.1); the pattern is an attribute.

— In an alignment-specifier (7.6.2); the pattern is the alignment-specifier without the ellipsis.

— In a capture-list (5.1.2); the pattern is a capture.

— In a sizeof... expression (5.3.3); the pattern is an identifier.

這裏是一個可能的解決方法是保證參數在左到右的順序計算:

struct expand_aux { 
    template<typename... Args> expand_aux(Args&&...) { } 
}; 

template<typename... Args> 
inline void expand(Args&&... args) 
{ 
    expand_aux temp { some_function(std::forward<Args>(args))... }; 
} 
6

至於說在另一個答案中,通過擴展參數包獲得的逗號不是逗號oparator,而是參數列表。將參數列表作爲表達式顯然是錯誤的。既然你不需要函數的返回值,你可以試一下在這行:

template <class... T> 
void ignore(T&&...) {} 

template<typename... Args> inline void expand(Args&&... args) 
{ 
    ignore(some_function(args)...); 
} 

然而,如果some_function回報void,包擴將無法正常工作,因爲你不能給作廢「價值「的功能。你可以返回一個值或鏈接每個呼叫some_function用逗號運算符:

template<typename... Args> inline void expand(Args&&... args) 
{ 
    ignore((some_function(args),true)...); 
    //or: 
    bool b[] = {(some_function(args),true)...}; 
} 
+1

好的破解! (剛剛刪除我的帖子,因爲昔日包括它) –

+0

+1爲最佳答案;)因爲布爾b [] = {};是非法的,它會更好地寫bool b [] = {true,(some_function(args),true)...};如果包裝是空的 – odinthenerd