4

次の例を検討してください。

#include <iostream>
#include <iostream>
#include <type_traits>

template<typename Type, template<typename> class Crtp>
class Base
{
    public:
        typedef int value;

        // f1: OK
        // Expected result: casts 4.2 to Base<Type, Crtp>::value
        value f1() {return 4.2;}

        // f2: NOT OK
        // Expected result: casts 4.2 to Crtp<Type>::value
        // But f2 does not compile: no type named 'value' 
        // in 'class Derived<double>'
        typename Crtp<Type>::value f2() {return 4.2;} 
};

template<typename Type>
class Derived : public Base<Type, Derived>
{
    public:
        typedef Type value;
};

int main()
{
    Derived<double> a;
    std::cout<<a.f1()<<std::endl;
    std::cout<<a.f2()<<std::endl;
    return 0;
}

この問題を解決するにはどうすればよいですか ( Derivedtypedef がBaseクラスから不明)。

編集:非常に単純なトリックを見つけました。以下が機能し、以前のバージョンが機能しない理由を誰かに説明してもらえますか? このトリックは標準の C++11 で問題ありませんか、それともコンパイラの動作方法 (ここでは g++ 4.7.1) が原因で機能しますか?

#include <iostream>
#include <iostream>
#include <type_traits>

template<typename Type, template<typename> class Crtp>
class Base
{
    public:
        typedef int value;
        value f1() {return 4.2;}
        template<typename T = Crtp<Type>> typename T::value f2() {return 4.2;}
};

template<typename Type>
class Derived : public Base<Type, Derived>
{
    public:
        typedef Type value;
};

int main()
{
    Derived<double> a;
    std::cout<<a.f1()<<std::endl;
    std::cout<<a.f2()<<std::endl;
    return 0;
}
4

2 に答える 2

3

value_getterを定義する前に宣言されているラッパークラス(ここでは)を使用する必要がありますBase。次に、定義する直前にそれを特殊化できますDerived

template<typename T>
struct value_getter;

template<typename Type, template<typename> class Crtp>
class Base
{
    public:
        typedef int value;

        value f1() {return 4.2;}

        // in 'class Derived<double>'
        typename value_getter<Crtp<Type> >::value f2() {return 4.2;} 
};

template<typename Type>
class Derived;

template<typename Type>
struct value_getter<Derived<Type> > {
    typedef Type value;
};

template<typename Type>
class Derived : public Base<Type, Derived>, public value_getter<Derived<Type> >
{
    public:
};

正確にはきれいではありませんが、少なくとも機能します。

于 2012-12-24T14:25:09.340 に答える
1

クラス Derived が完了すると、 f2 は実際に使用されるまでインスタンス化されないため、トリックは機能します。

あなたの特定の例では、これを行うことをお勧めします:

#include <iostream>
#include <iostream>
#include <type_traits>

template<typename Type, template<typename> class Crtp>
class Base
{
    public:
        typedef int value;

        value f1() {return 4.2;}

        Type f2() {return 4.2;} 
};

template<typename Type>
class Derived : public Base<Type, Derived>
{
    public:
        typedef Type value;
};

int main()
{
    Derived<double> a;
    std::cout<<a.f1()<<std::endl;
    std::cout<<a.f2()<<std::endl;
    return 0;
}

ただし、実際のコードには、それを非現実的にする他のニーズがある場合があります。

于 2012-12-24T15:08:59.023 に答える