2016-03-15 4 views
7

У меня есть следующий пример, в котором используются два параметра t1 и t2.Функция шаблона Variadic с более чем двумя параметрами

template<typename T> 
bool Compare(T t1, T t2) 
{ 
    return t1 == t2; 
} 

template<typename T, typename... Args> 
bool Compare(T t1, T t2, Args... args) 
{ 
    return (t1 == t2) && Compare(args...); 
} 

int main(void) 
{ 
    Compare(1, 1, "string", "string"); 
} 

Функция сравнения принимает пары параметров одного типа и их можно сравнить. Сравнение двух пар, после чего пакет параметров передается рекурсивно до тех пор, пока не будут достигнуты последние два параметра. Чтобы остановить рекурсию, я использую реализацию функции сравнения без пакета параметров.

Я хотел бы добавить третий аргумент t3 поэтому функция сравнения должно быть таким:

template<typename T> 
bool Compare(T t1, T t2, T t3) 
{ 
    return t1 == t2 == t3; 
} 

template<typename T, typename... Args> 
bool Compare(T t1, T t2, T t3, Args... args) 
{ 
    return (t1 == t2 == t3) && Compare(args...); 
} 

int main(void) 
{ 
    Compare(1, 1, 1, "string", "string", "string"); 
} 

Я ожидаю, что эта функция принимает три параметра для сравнения, то следующие три обрабатывается рекурсивно. Когда я пытаюсь скомпилировать этот код, я получить следующее сообщение об ошибке:

>xxx\source.cpp(4): error C2446: '==': no conversion from 'const char *' to 'int' 
1> xxx\source.cpp(4): note: There is no context in which this conversion is possible 
1> xxx\source.cpp(10): note: see reference to function template instantiation 'bool Compare<const char*>(T,T,T)' being compiled 
1>   with 
1>   [ 
1>    T=const char * 
1>   ] 
1> xxx\source.cpp(15): note: see reference to function template instantiation 'bool Compare<int,const char*,const char*,const char*>(T,T,T,const char *,const char *,const char *)' being compiled 
1>   with 
1>   [ 
1>    T=int 
1>   ] 
1>xxx\source.cpp(4): error C2040: '==': 'int' differs in levels of indirection from 'const char *' 

Как реализовать эту функцию, чтобы сравнить наборы из трех параметров одного и того же типа?

ответ

8
t1 == t2 == t3 

Это не проверяет t1, t2 и t3 все равны, он проверяет t1 равен t2, то проверяет, является ли полученный bool равно t3.

Может быть, что вы хотите вместо этого (предполагая, что разумные операторы равенства):

t1 == t2 && t1 == t3 

Так что ваш код будет выглядеть следующим образом:

template<typename T> 
bool Compare(T t1, T t2, T t3) 
{ 
    return t1 == t2 && t1 == t3; 
} 

template<typename T, typename... Args> 
bool Compare(T t1, T t2, T t3, Args... args) 
{ 
    return t1 == t2 && t1 == t3 && Compare(args...); 
} 

Обратите внимание, что ваш тестовый вызов с строковых литералов делает сравнение указателя , которые могут быть не такими, какие вы хотите.

+0

Для расширения на последнюю строку: прохождение c_str() из станда строки, содержащей «строку» в качестве одного из аргументов будет оценивать ложь, даже если все строки говорят «строка» - они имеют разные места в памяти , Вы можете предпочесть использовать std-строки (которые включают в себя обертывание строковых констант в них), когда это возможно. –

0

Это мое общее решение. compareConsecutive<N> вернет true, только если N последовательных аргументов равны для всех блоков из N аргументов.

#include <iostream> 
#include <tuple> 
#include <utility> 

template <std::size_t Start, typename IndexSequence> struct MakeIndexSequenceHelper; 

template <std::size_t Start, std::size_t... Is> 
struct MakeIndexSequenceHelper<Start, std::index_sequence<Is...>> { 
    using type = std::index_sequence<(Start + Is)...>; 
}; 

template <std::size_t Start, std::size_t Length> 
struct MakeIndexSequence : MakeIndexSequenceHelper<Start, std::make_index_sequence<Length>> {}; 

template <typename T, typename U> 
bool allAreSame (const T&, const U&) { 
    return false; 
} 

template <typename T> 
bool allAreSame (const T& t1, const T& t2) { 
    return t1 == t2; 
} 

template <typename T, typename U, typename... Args> 
bool allAreSame (const T&, const U&, const Args&...) { 
    return false; 
} 

template <typename T, typename... Args> 
bool allAreSame (const T& t1, const T& t2, const Args&... args) { 
    return allAreSame(t1, t2) && allAreSame(t1, args...); 
} 

template <typename Tuple, std::size_t... Is> 
bool allAreSameHelper (Tuple&& tuple, std::index_sequence<Is...>) { 
    return allAreSame (std::get<Is>(std::forward<Tuple>(tuple))...); 
} 

template <std::size_t N, typename... Args> 
bool allAreSameHelper (Args&&... args) { 
    return allAreSameHelper (std::forward_as_tuple(std::forward<Args>(args)...), std::make_index_sequence<N>{}); 
} 

template <std::size_t N, typename... Args> bool compareConsecutive (Args&&...); 

template <std::size_t N> 
bool compareConsecutive() {return true;} 

template <std::size_t N, typename Tuple, std::size_t... Is> 
bool compareConsecutiveHelper (Tuple&& tuple, std::index_sequence<Is...>) { 
    return compareConsecutive<N> (std::get<Is>(std::forward<Tuple>(tuple))...); 
} 

template <std::size_t N, std::size_t Start, std::size_t Length, typename... Args> 
bool compareConsecutiveHelper (Args&&... args) { 
    return compareConsecutiveHelper<N> (std::forward_as_tuple(std::forward<Args>(args)...), typename MakeIndexSequence<Start, Length>::type{}); 
} 

template <std::size_t N, typename... Args> 
bool compareConsecutive (Args&&... args) { 
    return allAreSameHelper<N>(std::forward<Args>(args)...) && compareConsecutiveHelper<N, N, sizeof...(Args) - N>(args...); 
} 

int main() { 
    std::cout << std::boolalpha << allAreSame("hi", "hi", "hi", "hi", "hi", "hi") << '\n'; // true 
    std::cout << compareConsecutive<2>(1, 1, "hi", "hi") << '\n'; // true 
    std::cout << compareConsecutive<2>(1, "hi", "hi", "hi") << '\n'; // false 
    std::cout << compareConsecutive<3>(1, 1, 1, "hi", "hi", "hi", 4.5, 4.5, 4.5) << '\n'; // true 
    std::cout << compareConsecutive<5>(1, 1, 1, 1, 1, "hi", "hi", "hi", "hi", "hi") << '\n'; // true 
    std::cout << compareConsecutive<5>(1, 1, 1, 1, 2, "hi", "hi", "hi", "hi", "hi") << '\n'; // false 
}