2011-05-21 125 views
6

這個問題被要求我在接受採訪時:模板功能

可以說,你有哪些可採取任何類型的參數和任意數量的參數的函數。 你將如何爲同樣的模板函數編寫?

我不知道確切的答案。有人可以建議嗎?

+1

什麼是你的答案嗎? – 2011-05-21 08:49:25

+0

正如我所說,我無法回答 – Vijay 2011-05-21 09:02:47

+2

實際上很抱歉成爲一個學生,但你說:「我不知道確切的答案。」 – 2011-05-21 09:03:40

回答

12

他們檢查你即將到來的C++標準的意識。新的功能被稱爲「可變參數模板」,看起來像這樣:

template<typename... Args> void f(const Args&... args) 
{ 
    // do something 
} 

對於更復雜的例子看,如this tutorial

+0

這不是說所有的參數都是相同的類型嗎? – 2011-05-21 08:51:52

+0

@George:不。 – ybungalobill 2011-05-21 08:52:32

+2

參數列表也可以是「Args && ...」,用於完美轉發。 – Philipp 2011-05-21 09:01:41

4

在C++ 03中,函數模板中的任何數量的參數都是不可能的。然而,對於任何類型的參數,你可以這樣寫:

template<typename T, typename U> 
void f(const T & t, const U &u) 
{ 
    //... 
} 
+3

我意識到這一點,但這並不回答我的問題 – Vijay 2011-05-21 09:03:45

+0

@Rahul:那麼你給了downvote?因爲你知道嗎? – Nawaz 2011-05-21 09:08:33

2

我同意,他們是最有可能尋找可變參數模板,但對於它的緣故,可以採取在C++ 03不同的方法:

使用變體類型

使用變體類型的容器。在這種情況下boost::variant是行不通的,因爲它限制類型的數量,但可以使用boost::any

void foo(std::vector<boost::any> args); 

相比可變參數模板,用戶代碼會更加麻煩,作爲代替書面方式foo(a, b, c, d),他們會必須手動創建向量的向量。語法可以通過可變參數宏(如果編譯器支持它們)和/或輔助模板函數來適應語法來簡化,但這很容易變得混亂。

的C方式(非模板):

使用省略號表示法編寫一個函數,它接受一個參數數目未知的(和類型):

void foo(type x, ...) 

這種方法有很多shortcommings。第一個是它不是類型安全的,編譯器將無法檢測到參數是正確的數字或​​類型,並且如果任何參數是非POD類型,則它是未定義的行爲,這限制了可用性從任何類型到POD類型,這可能或不是一個限制因素(你總是可以傳入一個指向非POD對象的指針)。總的來說,這是更復雜的處理,更容易出錯,所以應該避免。

一點也不

回答這個問題:在極少數情況下,單一的功能應該能夠採取未知數量的未知類型的參數。記錄和I/O可能需要這個,printf就是這樣的例子。但是這可以通過運算符重載(特別是operator<<)和鏈接在C++中處理。在評論bind已經建議,所以是的,在通用代碼完美轉發就是這樣的一個情況下,bindstd::thread ...

它認爲這是面試的一個很好的答案,你可以再討論一下對功能的實際需求是否存在,以及是否有更好的選擇。可以說,如果最後你確實需要一個變體類型的容器,你可以濫用運算符重載來簡化語法。這方面的例子將是boost::assign庫,並在這些線路,您可以創建一個輔助論據建設者爲:

class args { 
public: 
    args() {} 
    operator std::vector<boost::any>&() { 
     return v; 
    } 
    template <typename T> 
    args& operator,(T x) { 
     boost::any a = x; 
     v.push_back(a); 
     return *this; 
    } 
private: 
    std::vector<boost::any> v; 
}; 
// usage: 
void foo(std::vector<boost::any> a) { 
    std::cout << "Received " << a.size() << " arguments" << std::endl; 
} 
int main() { 
    foo((args(), 1, 5.0, "a string", std::vector<int>(5,10))); 
} 

可變參數模板

當然,這是一個C++ 0x中最好的選擇編譯器處理可變參數模板,不需要額外的鍋爐代碼,並且可以使編寫用戶代碼(直接作爲常規函數調用)和函數的實現(無論它是什麼)更簡單。作爲一種激勵的例子,建設有可變參數ARGS一個vector<boost::any>

typedef std::vector<boost::any> anyvector_t 

// Stop condition, adding nothing at the end 
void build_vector_impl(anyvector_t&) {} 

// Intermediate step, add a new argument to the vector and recurse: 
template <typename Head, typename... Tail> 
void build_vector_impl(anyvector_t& v, Head head, Tail... tail) { 
    v.push_back(boost::any(head)); 
    build_vector_impl(v, tail...); 
} 

// Syntactic sugar: make it return the vector: 
template <typename... Args> 
anyvector_t build_vector(Args... args) { 
    anyvector_t res; 
    build_vector_impl(res, args...); 
    return res; 
} 
// Test: 
int main() { 
    std::cout << "Number of args: " 
      << build_vector(1, 5, "Hi", std::vector<int>(5, 10)).size() 
      << std::endl; 
} 
+0

Visual Studio確實支持可變宏。 – Puppy 2011-05-21 11:23:43

+0

@DeadMG:更正後,當我和VS一起工作時,我們不得不支持VS2003/05/08,並且可能由於2003年的限制,禁止使用可變宏,因爲它們似乎在2005年可用。感謝提示。 – 2011-05-21 11:59:03

+0

「我仍然在單個函數中找到單一的情況......」std :: bind()? – ybungalobill 2011-05-21 12:07:31