2013-03-23 3 views
8

рассмотрим следующую функцию VARIADICЗаставить все && выполнить?

template <typename Type, typename... Types> 
bool f(Type& arg, Types&... args) 
{ 
    return f(arg) && f(args...); 
} 

template <typename Type> 
bool f(Type& arg) 
{ 
    // Do something 
} 

Если один уровень рекурсии false, то я подозреваю, что следующий не будет выполняться. Есть ли уловка для принудительной рекурсии по всем аргументам, даже если один из них возвращает false?

+1

Как о замене '&&' с '&'? – fredoverflow

ответ

21

Это не должно быть слишком трудно:

template <typename Type, typename... Types> 
bool f(Type& arg, Types&... args) 
{ 
    bool b1 = f(arg); 
    bool b2 = f(args...); 
    return b1 && b2; 
} 
+0

Я думаю, что просто избавлюсь от вторых вызовов 'f'. –

+0

@sftrabbit: Leftover :) Спасибо –

+0

См. Мой ответ для теста. – Vincent

4

Вы можете выполнять их по отдельности и возвращают логическое выражение:

bool b0 = f(arg); 
bool b1 = f(args); 
return b0 && b1; 
4

Без рекурсии:

template <typename... Types> 
bool f(Types&&... args) 
{ 
    bool r=true; 
    (void)std::initializer_list<bool>{(r = f(args)&&r)...}; 
    return r; 
} 
-1

Существует В гораздо приятнее, вместо & & между всеми функциями, просто используйте один &

static_cast<bool>(f(arg)) & static_cast<bool>(f2(args)) ... будет выполнять все операции, независимо от результата :)

+0

Если они не возвращают 'int' вместо' bool', а значения - '1' и' 2', и вы вдруг получаете 'false' вместо' true'. Извините, -1. –

+1

Это может быть исправлено с помощью 'static_cast '. Мне нравится этот подход, поскольку он более компактный, чем те, у которых есть вспомогательные переменные. – ipc

+0

Мне тоже нравится, литье int to boolean легко, и это приятно и компактно :), слишком плохие трюки дают такие отрицательные голоса: D, @Ipc изменен из-за комментария – Alon

11

Поскольку дискуссия развивалась в сравнении решения AndyProwl и Алон, я ve сравнивает оба решения, а результат ... зависит от количества аргументов.

Компиляция с:

g++-4.7 -std=c++11 -Wall -Wextra -O3 main.cpp -o main -D_FIRST 

тестов Решение AndyProwl и компилирования с:

g++-4.7 -std=c++11 -Wall -Wextra -O3 main.cpp -o main -D_SECOND 

тестов Решение Алон.

Вот программа эталонного теста для 10 аргументов.

#include <iostream> 
#include <chrono> 

// Function 1 : with && 
template <typename Type> 
inline bool f1(const Type& arg) 
{ 
    return arg; 
} 
template <typename Type, typename... Types> 
inline bool f1(const Type& arg, const Types&... args) 
{ 
    bool arg1 = f1(arg); 
    bool arg2 = f1(args...); 
    return arg1 && arg2; 
} 

// Function 2 : with & 
template <typename Type> 
inline bool f2(const Type& arg) 
{ 
    return arg; 
} 
template <typename Type, typename... Types> 
inline bool f2(const Type& arg, const Types&... args) 
{ 
    return f2(arg) & f2(args...); 
} 

// Benchmark 
int main(int argc, char* argv[]) 
{ 
    // Variables 
    static const unsigned long long int primes[10] = {11, 13, 17, 19, 23, 29, 31, 37, 41, 43}; 
    static const unsigned long long int nbenchs = 50; 
    static const unsigned long long int ntests = 10000000; 
    unsigned long long int sum = 0; 
    double result = 0; 
    double mean = 0; 
    std::chrono::high_resolution_clock::time_point t0 = std::chrono::high_resolution_clock::now(); 

    // Loop of benchmarks 
    for (unsigned long long int ibench = 0; ibench < nbenchs; ++ibench) { 

     // Initialization 
     t0 = std::chrono::high_resolution_clock::now(); 
     sum = 0; 

     // Loop of tests 
     for (unsigned long long int itest = 1; itest <= ntests; ++itest) { 
#ifdef _FIRST 
      sum += f1((itest+sum)%primes[0], (itest+sum)%primes[1], (itest+sum)%primes[2], (itest+sum)%primes[3], (itest+sum)%primes[4], (itest+sum)%primes[5], (itest+sum)%primes[6], (itest+sum)%primes[7], (itest+sum)%primes[8], (itest+sum)%primes[9]); 
#endif 
#ifdef _SECOND 
      sum += f2((itest+sum)%primes[0], (itest+sum)%primes[1], (itest+sum)%primes[2], (itest+sum)%primes[3], (itest+sum)%primes[4], (itest+sum)%primes[5], (itest+sum)%primes[6], (itest+sum)%primes[7], (itest+sum)%primes[8], (itest+sum)%primes[9]); 
#endif 
     } 

     // Finalization 
     result = std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::high_resolution_clock::now()-t0).count(); 
     mean += result; 
     std::cout<<"time = "<<result<<" (sum = "<<sum<<")"<<std::endl; 
    } 

    // End 
    std::cout<<"mean time = "<<mean/nbenchs<<std::endl; 
    return 0; 
} 

С 50 тестов для каждого раствора с заданным количеством аргументов, дисперсия очень мала, и среднее время, в течение этих тестов является надежным индикатором.

Мой первый тест был с «правильным» числом аргументов, где решение Alon быстрее, чем решение AndyProwl.

Окончательные результаты здесь:

Benchmark

Таким образом, решение AndyProwl, как правило, быстрее, чем Алон один. Итак, теперь я могу подтвердить ваш ответ. Но я думаю, что разница настолько мала, что это зависит от архитектуры/компилятора.

Итак:

  • AndyProwl + 1 для более быстрого решения, как правило
  • Алон + 1 для constexpr готовые решения
+2

Хороший график, спасибо за обмен информацией. +1 –

+0

Все графики нуждаются в ошибках – Inverse

+0

Как я уже опубликовал код, вы можете запустить его несколько раз и вычислить дисперсию. – Vincent

Смежные вопросы