2014-01-17 48 views
2
無限相同的數字

我怎樣才能接受字符串的相同編號的功能 - INT - 焦函數接受3種

func("aa","sd","zzz",123,13,3,'w','a','x') //correct 
func("aa","sd",123,3,'w','x') //correct 
func("aa",2,'w') //correct 
func()//correct 
func("aa","VV",23,'w') //error because 2 string 1 int and 1 char 
func('a',2) //error 0 string 1 char 1 int 
..... 

我想不是在運行時檢查在編譯時變量,所以我不能使用std::vector

任何想法?可能嗎 ?

+0

你嘗試雜物更方便ble參數的功能? – Dinesh

+0

@Dinesh如果你的意思是variadic模板,stdarg,...是的,我試過了,但我找不到解決方案。 – Omid

+0

@Dinesh:這不會允許'func()',因爲可變參數必須至少有一個固定的參數。它也不會拒絕'func(「aa」,「VV」,23,'w')'。 –

回答

2

在C++ 11的一個簡單方法是:

template <std::size_t N> 
void func(const std::array<const char*, N>& cstrings, 
      const std::array<int, N>& ints 
      const std::array<char, N>& chars); 

所以你可以使用它:

func({ "aa","sd","zzz"}, {123, 13, 3} , {'w', 'a', 'x'}); 

如果你想使用相同的語法,它更詳細和使用SFINAE: 它退到調用版本std::array,因爲它是實現

#include <cstdint> 
#include <array> 
#include <tuple> 
#include <type_traits> 

#if 1 // Not in C++11 

template <std::size_t ...> struct index_sequence {}; 

template <std::size_t I, std::size_t ...Is> 
struct make_index_sequence : make_index_sequence < I - 1, I - 1, Is... > {}; 

template <std::size_t ... Is> 
struct make_index_sequence<0, Is...> : index_sequence<Is...> { 
    typedef index_sequence<Is...> type; 
}; 

#endif 

template <std::size_t N> 
void func(const std::array<const char*, N>& cstrings, 
      const std::array<int, N>& ints 
      const std::array<char, N>& chars) 
{ 
    // Add your code here 
} 

namespace detail 
{ 
    template <typename T, typename SEQ, typename SEQ2> struct helper_split3; 

    template <typename ... Ts, std::size_t ... Is, std::size_t ... Is2> 
    struct helper_split3<std::tuple<Ts...>, index_sequence<Is...>, index_sequence<Is2...> > 
    { 
     typedef std::tuple<typename std::tuple_element<Is, std::tuple<Ts...> >::type...> First; 
     typedef std::tuple<typename std::tuple_element<sizeof...(Is) + Is, std::tuple<Ts...> >::type...> Middle; 
     typedef std::tuple<typename std::tuple_element<2 * sizeof...(Is) + Is2, std::tuple<Ts...> >::type...> Last; 
    }; 

    template <typename T, typename ... Ts> struct are_same : std::true_type {}; 

    template <typename T, typename Tail, typename ... Ts> 
    struct are_same<T, Tail, Ts...> : 
     std::conditional<std::is_same<T, Tail>::value && are_same<T, Ts...>::value, 
         std::true_type, std::false_type>::type {}; 

    template <typename T, typename Tuple> struct are_same_in_tuple; 

    template <typename T, typename ... Ts> 
    struct are_same_in_tuple<T, std::tuple<Ts...>> : are_same<T, Ts...> {}; 

    template<typename ... Ts> 
    struct func_trait 
    { 
     typedef helper_split3<std::tuple<Ts...>, 
       typename make_index_sequence<sizeof...(Ts)/3>::type, 
       typename make_index_sequence<sizeof...(Ts) - 2 * (sizeof...(Ts)/3)>::type> 
       helper; 

     static const bool value = (sizeof...(Ts) % 3 == 0) 
            && are_same_in_tuple<const char*, typename helper::First>::value 
            && are_same_in_tuple<int, typename helper::Middle>::value 
            && are_same_in_tuple<char, typename helper::Last>::value; 
    }; 

    template <typename ... Ts, std::size_t ... Is> 
    void func(std::tuple<Ts...>&& t, index_sequence<Is...>) 
    { 
     constexpr std::size_t N = sizeof...(Ts); 
     ::func<N>(std::array<const char*, N>({std::get<Is>(t)...}), 
        std::array<int, N>({std::get<sizeof...(Is) + Is>(t)...}), 
        std::array<char, N>({std::get<2 * sizeof...(Is) + Is>(t)...})); 
    } 

} // namespace detail 

template <typename ... Ts> 
typename std::enable_if<detail::func_trait<Ts...>::value, void>::type 
func(Ts...args) 
{ 
    detail::func(std::tie(args...), make_index_sequence<sizeof...(Ts)/3>()); 
} 
+0

Ty,但我不能運行你的第二個代碼它給出了50個錯誤!你能分享你的完整代碼嗎? – Omid

+0

@omid:完成:http://ideone.com/DTIYNN – Jarod42

-1

你不能按照你的要求來這樣做。你最好的辦法是製作一個包含這三種類型的結構類型,並傳入可變數目的這些結構。

4

假設你的參數看起來是這樣的:

struct Param 
{ 
    string mS; 
    char mC; 
    int mN; 
}; 

而不是試圖組成一個函數,它接受一個未知的或可變數量的參數,具備的功能需要vector

void func (const vector <Param>& parameters) 

更重要的是,具備的功能需要一對迭代器來表示矢量:

void func (vector <Param>::const_iterator begin, vector <Param>::const_iterator end) 

更棒的是,泛化容器和迭代器:

template <typename Iterator> void func (Iterator begin, Iterator end) 

在最後情況下,迭代器可以引用任何符合迭代器限制的東西。這包括C風格的數組。您可以使用此類似這樣的:

void Doer() 
{ 
    Params params[] = 
    { 
    Param("aa",123, 'W'), 
    Param("sd",13,'a'), 
    Param("zzz",3,'x') 
    }; 
    const size_t numParams = sizeof (params)/sizeof (params[0]); 
    func (params, params + numParams); 
} 

當然,你需要一個構造函數:

struct Param 
{ 
    Param (const std::string s, int n, char c) 
    : 
    mS (s), 
    mN (n), 
    mC (c) 
    { 
    } 
// ... 
}; 

而且在某些情況下,你可能需要一個壺型功能:

Param make_param (const std::string& s, int n, char c) 
{ 
    Param retval (s, n, c); 
    return retval; 
} 
4

(這個問題最初被標記爲C和C++;後來C標記被刪除了。以下部分特定於C,但我將它留在這裏以防其他人使用它。)

在C中,不,我不相信可以通過編譯時檢查來做到這一點。變量函數(a)至少需要一個固定的參數(不包括你的例子),(b)在編譯時不檢查可變參數的類型。 Variadic宏(C99中的新增功能)可能更有前途,但它們不執行類型檢查。我想過如何用嵌套的通用選擇(C11中的一個新功能,C++中不存在)來完成此任務,但我不相信他們能解決問題。

如果您正在使用C(這個問題最初標記C和C++),我認爲你可以得到的最接近的是有參數的每個數字一個獨特的功能:

void func0(void); 
void func1(char*, int, char);  
void func2(char*, char*, int, int, char, char); 
void func3(char*, char*, char*, int, int, int, char, char, char); 

你知道當你正在寫電話時,你傳遞了多少個參數,所以指定一個不同的函數並不是太大的負擔。

在C++中,你可以提供多個重載函數,每個採取適當類型的參數:

void func(); 
void func(char*, int, char);  
void func(char*, char*, int, int, char, char); 
void func(char*, char*, char*, int, int, int, char, char, char); 

等等,儘可能多的超載,你有耐心。

這些解決方案都不能無限擴展到任意數量的參數。

我曾經認爲在C++中沒有通用的解決方案,但Jarod42's answer(我還沒有花時間理解)似乎已經顯示出其他方面。另一方面,爲了簡單起見,有些事情可以說。另一方面,你只需要寫一次。

一兩件事:你的最後一個例子是:

func('a',2) //error 0 string 1 char 1 int 

在C,兩者'a'2都是同一類型的,即int。在C++中,a的類型爲char。 (同樣,如果你只關心C這個不一定相關++)

+0

有可能使用SFINAE檢查編譯類型的參數類型...查看我的答案。 – Jarod42

+0

我最初誤解了這個問題,因爲某些原因,OP想讓所有參數都是相同的類型。我已將它更新爲(嘗試)回答實際問題。但@ Jarod42的答案可能會更好。 –

+0

@MattMcNabb:關於C中'void func0(void)'的好處;我更新了這個例子。但是,不能在參數數量上重載宏。 –

1

在C和C++,編寫variadic functions時,有三大原則:

  1. 您必須知道大小和第一個參數的類型。
  2. 您必須能夠推斷剩餘參數的大小和類型。
  3. 你必須知道你何時到達最後一個參數。

這就是printf這樣的功能是如何工作的。
它的第一個參數始終是char*
下一組參數由找到的%x格式化程序決定。
它在到達最後一個百分比說明符時知道它的參數。

如果你可以遵循這三條規則,任何編寫可變參數函數的在線指南都將幫助你完成你所追求的內容。