2012-12-17 128 views
3

我寫一個函數inListi(),它至少需要一個參數,第一個參數的所有後續參數THES列表進行比較。如果第一個參數==列表中的元素則返回true,否則返回false。所以:問題專門變量函數模板

if(inListi(1.2, 2.3, 4.5, 1.2)) 
    std::cout << "Returns true because last argument equals the first argument." << endl; 

if(inListi("hello", "world", "HEllo")) 
    std::cout << "This should print out because of the last argument." << endl; 

問題是,它不起作用。我有下面的代碼。對於char [N],我複製 陣列的N個部分成一個字符串,然後再繼續。我想這樣做,因爲我可能會傳遞一個非空終止的char [N]。

反正,所述代碼如下。大多數代碼是冗餘的,處理const和一個參數的組合是const [N],另一個不是那種類型。 (順便說一下,有減少這種重複的方法嗎?)

#include <iostream> 
#include <stdexcept> 
#include <string> 
#include <sstream> 
#include <typeinfo> 
#include <type_traits> 

#include <boost/algorithm/string.hpp> 

using namespace std; 

//////////////////////////////////////////////////////////////////////////////// 
// inListi 
//////////////////////////////////////////////////////////////////////////////// 
template<typename T> 
bool inListi(T&& value) 
{ 
    return false; 
} 


template<typename FirstType, typename SecondType, typename ... Rest> 
bool inListi(FirstType&& first, SecondType&& second, Rest ... rest) 
{ 
    cout << "GENERIC inListi" << endl; 
    cout << "first is " << typeid(first).name() << endl; 
    cout << "second is " << typeid(second).name() << endl; 

    if(first == second) 
     return true; 
    else return inListi(first, rest...); 
} 


// We specialize the inListi for strings. We lower the case. 
// but what if char[n] is passed? We have specializations that 
// convert that to strings. 
template<typename ... Rest> 
bool inListi(string &&first, string &&second, Rest ... rest) { 
    string lFirst = first; 
    string lSecond = second; 

    cout << "LOWERED" << endl; 

    boost::algorithm::to_lower(lFirst); 
    boost::algorithm::to_lower(lSecond); 

    if(lFirst == lSecond) 
     return true; 
    else return inListi(first, rest...); 
} 



// Specializations for when we are given char-arrays. We copy the 
// the arrays into a string upto the size of the array. This is done 
// to take care of the case of when the char-array is not nul-terminated. 
// The amount repetition is to permutate over which argument is a char-array 
// and also for const-ness. 
template<int F, typename SecondType, typename ... Rest> 
bool inListi(char (&&first)[F], SecondType &&second, Rest ... rest) { 
    string strFirst = string(first, F); 
    cout << "arr, type, rest" << endl; 
    return inListi(strFirst, second, rest...); 
} 
template<int F, typename SecondType, typename ... Rest> 
bool inListi(const char (&&first)[F], SecondType &&second, Rest ... rest) { 
    string strFirst = string(first, F); 
    cout << "const arr, type, rest" << endl; 
    return inListi(strFirst, second, rest...); 
} 
template<typename FirstType, int S, typename ... Rest> 
bool inListi(FirstType &&first, char (&&second)[S], Rest ... rest) { 
    string strSecond = string(second, S); 
    cout << "type, arr, rest" << endl; 
    return inListi(first, strSecond, rest...); 
} 
template<typename FirstType, int S, typename ... Rest> 
bool inListi(FirstType &&first, const char (&&second)[S], Rest ... rest) { 
    string strSecond = string(second, S); 
    cout << "type, const arr, rest" << endl; 
    return inListi(first, strSecond, rest...); 
} 
template<int F, int S, typename ... Rest> 
bool inListi(char (&&first)[F], char (&&second)[S], Rest ... rest) { 
    string strFirst = string(first, F); 
    string strSecond = string(second, S); 
    cout << "arr, arr, rest" << endl; 
    return inListi(strFirst, strSecond, rest...); 
} 
template<int F, int S, typename ... Rest> 
bool inListi(const char (&&first)[F], char (&&second)[S], Rest ... rest) { 
    string strFirst = string(first, F); 
    string strSecond = string(second, S); 
    cout << "const arr, arr, rest" << endl; 
    return inListi(strFirst, strSecond, rest...); 
} 
template<int F, int S, typename ... Rest> 
bool inListi(char (&&first)[F], const char (&&second)[S], Rest ... rest) { 
    string strFirst = string(first, F); 
    string strSecond = string(second, S); 
    cout << "arr, const arr, rest" << endl; 
    return inListi(strFirst, strSecond, rest...); 
} 
template<int F, int S, typename ... Rest> 
bool inListi(const char (&&first)[F], const char (&&second)[S], Rest ... rest) { 
    string strFirst = string(first, F); 
    string strSecond = string(second, S); 
    cout << "const arr, const arr, rest" << endl; 
    return inListi(strFirst, strSecond, rest...); 
} 


int main() { 

    if(inListi("Hello", "World", "HEllo")) 
     cout << "Hello is in the listi." << endl; 
    else 
     cout << "Hello is not in the listi." << endl; 

    return 0; 
} 

的程序的輸出是下面的:

[bitdiot foo]$ g++ forStackOverflow.cpp -std=gnu++0x 
[bitdiot foo]$ ./a.out 
GENERIC inListi 
first is A6_c 
second is A6_c 
GENERIC inListi 
first is A6_c 
second is PKc 
Hello is not in the listi. 

通知,即沒有中間代碼的被調用時,它直接使用通用版本。另外,看起來很奇怪的另一件事是'PKc'。我假設的是鍵入char *。現在,它爲什麼會有不同的類型?

不管怎麼說,謝謝!

回答

2

看起來你可以使用一個重載const char*(這也許是什麼PKc指)。

也許是這樣的:

template<typename ... Rest> 
bool inListi(const char *first, const char *second, Rest... rest) { 
    cout << "const char*, const char*, rest" << endl; 
    return inListi(string(first), string(second), rest...); 
} 

兩個其他的東西:

  • 注意使用的臨時的,這樣我們就稱之爲string&&版本
  • 一個const char*超載將匹配的第一個電話,但你可能需要更多的重載處理後續調用

另一個編輯:上prevent array decay in parameter pack expansion一些很好的意見向我們展示瞭如何可以通過使用該參數包右值引用來完成:

#include <iostream> 
#include <string> 
#include <utility> 
#include <algorithm> 
#include <cctype> 

template <typename T> 
bool inListi(T&& value) 
{ 
    return false; 
} 

template <typename FirstType, typename SecondType, typename... Rest> 
bool inListi(FirstType&& first, SecondType&& second, Rest&&... rest) 
{ 
    if (first == second) 
    return true; 
    else 
    return inListi(std::forward<FirstType&&>(first), rest...); 
} 

template <int N, int M, typename... Rest> 
bool inListi(char (&first)[N], char (&second)[M], Rest&&... rest) 
{ 
    std::string lFirst(first, N); 
    std::transform(lFirst.begin(), lFirst.end(), lFirst.begin(), ::tolower); 
    std::string lSecond(second, M); 
    std::transform(lSecond.begin(), lSecond.end(), lSecond.begin(), ::tolower); 

    if (lFirst == lSecond) 
    return true; 
    else 
    return inListi(first, rest...); 
} 

template <typename... Rest> 
bool inListi(const char *first, const char *second, Rest&&... rest) 
{ 
    std::string lFirst(first); 
    std::transform(lFirst.begin(), lFirst.end(), lFirst.begin(), ::tolower); 
    std::string lSecond(second); 
    std::transform(lSecond.begin(), lSecond.end(), lSecond.begin(), ::tolower); 

    if (lFirst == lSecond) 
    return true; 
    else 
    return inListi(first, rest...); 
} 

int main() { 
    char a[5] = {'H','e','l','l','o'}; 
    char b[5] = {'W','o','r','l','d'}; 
    char c[5] = {'H','E','l','l','o'}; 
    std::cout << inListi(a, b, c) << '\n'; 
    std::cout << inListi("Hello", "World", "HEllo") << '\n'; 
    std::cout << inListi(5, 42, 5) << '\n'; 
} 

這個工作,只要所有的參數都相同類型。如果你想開始混合類型,你可能需要開始編寫所有適當的重載對。

+0

感謝您的及時響應。我通過聲明兩個字符串局部變量併爲它們分配第一個和第二個參數來修改此代碼。該代碼確實被調用,但(字符串,字符串,休息)代碼不會被調用,而是跳轉到通用版本。所以(string,string,rest)中的to_lower代碼永遠不會被調用。有什麼建議麼? – Bitdiot

+0

嘗試添加(字符串,字符串)重載。 –

+0

再次感謝。我在原始代碼中有一個(字符串,字符串,休息)版本。但是我添加了一個(字符串,字符串)版本而沒有其餘的,它仍然調用通用代碼。 – Bitdiot