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;
}

如何解决这个问题(类Derived中的 typedef 未知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

您的技巧有效,因为 f2 现在在实际使用它之前不会被实例化,此时 Derived 类已经完成。

在您的特定示例中,我可能只建议这样做:

#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 回答