1

ブーストの多倍数で少し遊んでみると、次のエラーが発生しました

In file included from main.cpp:1:
In file included from /usr/include/boost/multiprecision/cpp_int.hpp:12:
In file included from /usr/include/boost/multiprecision/number.hpp:16:
In file included from /usr/include/boost/type_traits/is_signed.hpp:15:
In file included from /usr/include/boost/type_traits/is_enum.hpp:14:
In file included from /usr/include/boost/type_traits/intrinsics.hpp:149:
/usr/include/boost/type_traits/is_reference.hpp:32:19: fatal error: recursive template instantiation exceeded maximum
      depth of 256

インスタンス化エラーの署名を含む多くの行が続きます。次のコードをコンパイルしたときに問題が発生しました。

#include<boost/multiprecision/cpp_int.hpp>

using big_int = boost::multiprecision::cpp_int;

big_int getOne(big_int){ return (big_int) 1;}

template<typename T, typename U>
T fastPowMod(T a, U b, T p){
    if(b==0)
        return getOne(a);
    if(b%2 != 0){
        return (a*fastPowMod(a,b-1,p))%p;
    }
    else{
        T aux = fastPowMod(a,b/2,p);
        return (aux*aux)%p;
    }
}

int main(){
    std::cout << fastPowMod<big_int,big_int>(108041234,180611234, 81243) std::endl;
}

clang++ -std=c++11 main.cpp

このコードは、通常の整数でインスタンス化すると完全に正常にコンパイルされるため、なぜこれが起こるのかわかりません。

編集:私は自分自身に答えます。テンプレートと再帰を扱うときは常に明示的であることを忘れないでください!

template<typename T, typename U>
T fastPowMod(T a, U b, T p){
    if(b==0)
        return getOne(a);
    if(b%2 != 0){
        return (a*fastPowMod<T,U>(a,b-1,p))%p;
    }
    else{
        T aux = fastPowMod<T,U>(a,b/2,p);
        return (aux*aux)%p;
    }
}
4

1 に答える 1

0

あなたの回避策には理解が欠けています。

この問題は、コンパイラが遅延評価された式テンプレートを返すときに発生します。これにより、 の再帰の各レベルで異なるインスタンス化をfastPowMod無限にインスタンス化するための再帰呼び出しが発生します。

提案された修正は、再帰呼び出しへの引数を強制的に評価することで無効にします。

同様に、ET を完全に無効にすることもできます。

using big_int = bmp::number<bmp::cpp_int::backend_type, bmp::et_off>;

この特定のケースでは、再帰を反復にモーフィングすることを検討することをお勧めします。これは、ユーザーまたはコンパイラーが一度にいくつかの反復を展開する可能性があります。このようにして、遅延評価の利点を保持できます。

于 2015-11-13T15:18:04.980 に答える