Mixing typedef and CRTP?

Mixing typedef and CRTP?

本文关键字:CRTP and typedef Mixing      更新时间:2023-10-16

考虑以下示例:

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

您必须使用包装类别(在这里是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:
};

它并不完全漂亮,但至少可以起作用。

您的技巧有效,因为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;
}

但是您的真实代码可能具有使这不切实际的其他需求。