4

このコードの何が問題になっていますか?

#include <iostream>

template<unsigned int N, unsigned int P=0>
constexpr unsigned int Log2() {
    return (N <= 1) ? P : Log2<N/2,P+1>();
}

int main()
{
    std::cout << "Log2(8) = " << Log2<8>() << std::endl;
    return 0;
}

でコンパイルするとgcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)、次のエラーが発生します。

log2.cpp: In function ‘constexpr unsigned int Log2() [with unsigned int N = 0u, unsigned int P = 1023u]’:
log2.cpp:5:38: error: template instantiation depth exceeds maximum of 1024 (use -ftemplate-depth= to increase the maximum) instantiating ‘constexpr unsigned int Log2() [with unsigned int N = 0u, unsigned int P = 1024u]’
log2.cpp:5:38:   recursively instantiated from ‘constexpr unsigned int Log2() [with unsigned int N = 4u, unsigned int P = 1u]’
log2.cpp:5:38:   instantiated from ‘constexpr unsigned int Log2() [with unsigned int N = 8u, unsigned int P = 0u]’
log2.cpp:10:37:   instantiated from here
4

2 に答える 2

5

他の人がすでに言ったように: コンパイラは、if/elseまたは三項演算子などの条件式を評価しません?:。ただし、この条件式をコンパイル時に行う方法はまだあります。

#include <cstddef>     // size_t is shorter than unsigned int, it's a matter of taste in this case
#include <iostream>    // to show our results
#include <type_traits> // needed for the mighty std::enable_if

template<size_t N, size_t P = 0>
constexpr typename std::enable_if<(N <= 1), size_t>::type Log2()
{
   return P;
}

template<size_t N, size_t P = 0>
constexpr typename std::enable_if<!(N <= 1), size_t>::type Log2()
{
   return Log2<N / 2, P + 1>();
}

int main()
{
   std::cout << Log2<1>() << "\n";
   std::cout << Log2<2>() << "\n";
   std::cout << Log2<4>() << "\n";
   std::cout << Log2<8>() << "\n";
   std::cout << Log2<16>() << "\n";
}

これが何をするかはかなり明白です: Ifの場合N <= 1、最初のブランチが評価される必要があるため、Log2<0, P>()andLog2<1, P>()は に評価されPます。の場合N <= 1、この関数ヘッダーが有効であるため、上のメソッドが有効になります。他のすべて、つまりN >= 2or!(N <= 1)については、再帰する必要があります。これは 2 番目の方法で行われます。

于 2013-08-14T13:25:03.920 に答える