8

次の可変長関数を考えてみましょう

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
} 

再帰の 1 つのレベルが である場合false、以下は実行されないのではないかと思います。それらの1つが返されたとしても、すべての引数に再帰を強制するトリックはありますfalseか?

4

5 に答える 5

21

これはそれほど難しいことではありません:

template <typename Type, typename... Types>
bool f(Type& arg, Types&... args)
{
    bool b1 = f(arg);
    bool b2 = f(args...);
    return b1 && b2;
}
于 2013-03-23T15:02:34.870 に答える
10

AndyProwl と Alon のソリューションの比較で議論が発展したので、私は両方のソリューションをベンチマークしました。結果は ... 引数の数によって異なります。

コンパイル:

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

Alon ソリューションのベンチマークです。

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 ソリューションよりも高速である「適切な」数の引数を使用したものです。

最終結果は次のとおりです。

基準

したがって、AndyProwl ソリューションは一般的に Alon ソリューションよりも高速です。これで、あなたの答えを検証できます。しかし、違いは非常に小さいため、アーキテクチャ/コンパイラに依存していると思います。

そう:

  • 一般的に高速なソリューションの場合は AndyProwl+1
  • constexpr 対応ソリューションの Alon+1
于 2013-03-23T18:17:38.210 に答える
4

再帰なし:

template <typename... Types>
bool f(Types&&... args)
{
  bool r=true;
  (void)std::initializer_list<bool>{(r = f(args)&&r)...};
  return r;
}
于 2013-03-23T15:06:28.367 に答える
4

それらを個別に実行して、bool 式を返すことができます。

bool b0 = f(arg);
bool b1 = f(args);
return b0 && b1;
于 2013-03-23T15:03:37.987 に答える
-2

すべての関数間で&&を使用する代わりに、1つの&を使用するだけで、はるかに優れたトリックがあります。

static_cast<bool>(f(arg)) & static_cast<bool>(f2(args)) ...結果に関係なくすべての操作を実行します:)

于 2013-03-23T15:07:17.617 に答える