curiously recurring template pattern problem

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • John Harrison

    curiously recurring template pattern problem

    The following code does not compile

    template <class Derived>
    struct X
    {
    typedef typename Derived::type type;
    };

    struct Y : public X<Y>
    {
    typedef int type;
    };

    int main()
    {
    }

    gcc and VC++ 7 give unhelpful error messages but Comeau C++ says 'incomplete
    type is not allowed' pointing at the typedef in X.

    Can someone explain to my why this should be a problem? I'm presuming that
    this kind of construct is difficult or impossible to compile for some
    reason.

    Secondly is there a way to achieve what I want, which is to let X know the
    definition of a type defined in any class derived from X, by passing the
    derived type as a template parameter to X (aka the curiously recurring
    template pattern).

    Thanks,
    john


  • Rolf Magnus

    #2
    Re: curiously recurring template pattern problem

    John Harrison wrote:
    [color=blue]
    > The following code does not compile
    >
    > template <class Derived>
    > struct X
    > {
    > typedef typename Derived::type type;
    > };
    >
    > struct Y : public X<Y>[/color]

    At this point, Y is incomplete, but X must be instantiated based on Y.
    The compiler doesn't yet know Y::type. At least that's how I think it
    works. I don't know a solution to your problem.
    [color=blue]
    > {
    > typedef int type;
    > };
    >
    > int main()
    > {
    > }[/color]

    Comment

    • Rolf Magnus

      #3
      Re: curiously recurring template pattern problem

      John Harrison wrote:
      [color=blue]
      > The following code does not compile
      >
      > template <class Derived>
      > struct X
      > {
      > typedef typename Derived::type type;
      > };
      >
      > struct Y : public X<Y>[/color]

      At this point, Y is incomplete, but X must be instantiated based on Y.
      The compiler doesn't yet know Y::type. At least that's how I think it
      works. I don't know a solution to your problem.
      [color=blue]
      > {
      > typedef int type;
      > };
      >
      > int main()
      > {
      > }[/color]

      Comment

      • Denis Remezov

        #4
        Re: curiously recurring template pattern problem

        John Harrison wrote:[color=blue]
        >[/color]
        [snip][color=blue]
        >
        > Secondly is there a way to achieve what I want, which is to let X know the
        > definition of a type defined in any class derived from X, by passing the
        > derived type as a template parameter to X (aka the curiously recurring
        > template pattern).
        >
        > Thanks,
        > john[/color]


        How about this:

        template <class DerivedTraits, class Derived>
        struct X
        {
        // typedef typename Derived::type type;
        typedef typename DerivedTraits:: type type;
        };

        struct YTraits {
        typedef int type;
        };

        struct Y : public YTraits, X<YTraits, Y>
        {
        // typedef int type;
        };


        Denis

        Comment

        • Denis Remezov

          #5
          Re: curiously recurring template pattern problem

          John Harrison wrote:[color=blue]
          >[/color]
          [snip][color=blue]
          >
          > Secondly is there a way to achieve what I want, which is to let X know the
          > definition of a type defined in any class derived from X, by passing the
          > derived type as a template parameter to X (aka the curiously recurring
          > template pattern).
          >
          > Thanks,
          > john[/color]


          How about this:

          template <class DerivedTraits, class Derived>
          struct X
          {
          // typedef typename Derived::type type;
          typedef typename DerivedTraits:: type type;
          };

          struct YTraits {
          typedef int type;
          };

          struct Y : public YTraits, X<YTraits, Y>
          {
          // typedef int type;
          };


          Denis

          Comment

          • Chris Theis

            #6
            Re: curiously recurring template pattern problem

            "John Harrison" <john_andronicu s@hotmail.com> wrote in message
            news:c509lr$2nl 3hi$1@ID-196037.news.uni-berlin.de...[color=blue]
            > The following code does not compile
            >
            > template <class Derived>
            > struct X
            > {
            > typedef typename Derived::type type;
            > };
            >
            > struct Y : public X<Y>
            > {
            > typedef int type;
            > };
            >
            > int main()
            > {
            > }
            >
            > gcc and VC++ 7 give unhelpful error messages but Comeau C++ says[/color]
            'incomplete[color=blue]
            > type is not allowed' pointing at the typedef in X.[/color]

            Hi John,

            Interesting thing - to me it seems that this is a problem regarding the
            order of how and when the template parameters are substituted and when
            typedefs are resolved. However, I´m not an expert on compiler techniques so
            I´d also be interested if somebody could shed some more light onto this,
            please.
            [color=blue]
            >
            > Can someone explain to my why this should be a problem? I'm presuming that
            > this kind of construct is difficult or impossible to compile for some
            > reason.
            >[/color]
            [SNIP]

            There is a way to circumvent this (IMHO probably correct behavior) by using
            templates only instead of typedefs.

            template <class Derived, typename DerivedType>
            struct X
            {
            X() {};
            ~X() {};
            void test() { cout << typeid( type ).name() << endl; };
            typedef typename DerivedType type;
            };

            template<typena me InternalType>
            struct Y : public X<Y, InternalType>
            {
            Y() {};
            ~Y() {};
            };

            int main()
            {
            Y<int> MyObj;
            MyObj.test();
            return 1;
            }

            HTH
            Chris


            Comment

            • Chris Theis

              #7
              Re: curiously recurring template pattern problem

              "John Harrison" <john_andronicu s@hotmail.com> wrote in message
              news:c509lr$2nl 3hi$1@ID-196037.news.uni-berlin.de...[color=blue]
              > The following code does not compile
              >
              > template <class Derived>
              > struct X
              > {
              > typedef typename Derived::type type;
              > };
              >
              > struct Y : public X<Y>
              > {
              > typedef int type;
              > };
              >
              > int main()
              > {
              > }
              >
              > gcc and VC++ 7 give unhelpful error messages but Comeau C++ says[/color]
              'incomplete[color=blue]
              > type is not allowed' pointing at the typedef in X.[/color]

              Hi John,

              Interesting thing - to me it seems that this is a problem regarding the
              order of how and when the template parameters are substituted and when
              typedefs are resolved. However, I´m not an expert on compiler techniques so
              I´d also be interested if somebody could shed some more light onto this,
              please.
              [color=blue]
              >
              > Can someone explain to my why this should be a problem? I'm presuming that
              > this kind of construct is difficult or impossible to compile for some
              > reason.
              >[/color]
              [SNIP]

              There is a way to circumvent this (IMHO probably correct behavior) by using
              templates only instead of typedefs.

              template <class Derived, typename DerivedType>
              struct X
              {
              X() {};
              ~X() {};
              void test() { cout << typeid( type ).name() << endl; };
              typedef typename DerivedType type;
              };

              template<typena me InternalType>
              struct Y : public X<Y, InternalType>
              {
              Y() {};
              ~Y() {};
              };

              int main()
              {
              Y<int> MyObj;
              MyObj.test();
              return 1;
              }

              HTH
              Chris


              Comment

              • Denis Remezov

                #8
                Re: curiously recurring template pattern problem

                Denis Remezov wrote:[color=blue]
                >
                > John Harrison wrote:[color=green]
                > >[/color]
                > [snip][color=green]
                > >
                > > Secondly is there a way to achieve what I want, which is to let X know the
                > > definition of a type defined in any class derived from X, by passing the
                > > derived type as a template parameter to X (aka the curiously recurring
                > > template pattern).
                > >
                > > Thanks,
                > > john[/color]
                >
                > How about this:
                >
                > template <class DerivedTraits, class Derived>
                > struct X
                > {
                > // typedef typename Derived::type type;
                > typedef typename DerivedTraits:: type type;
                > };
                >
                > struct YTraits {
                > typedef int type;
                > };
                >
                > struct Y : public YTraits, X<YTraits, Y>
                > {
                > // typedef int type;
                > };
                >
                > Denis[/color]

                In other words, I meant refactoring the derived class into two parts, the
                first of which does not depend on X, then using it as above. Doing so breaks
                the circular dependence of the original scheme, in which X gets parsed first,
                attempting to look up names to be declared in Y, which hasn't been parsed
                yet because it has X as a base. A bit of a prop to the compiler here.

                Denis

                Comment

                • Denis Remezov

                  #9
                  Re: curiously recurring template pattern problem

                  Denis Remezov wrote:[color=blue]
                  >
                  > John Harrison wrote:[color=green]
                  > >[/color]
                  > [snip][color=green]
                  > >
                  > > Secondly is there a way to achieve what I want, which is to let X know the
                  > > definition of a type defined in any class derived from X, by passing the
                  > > derived type as a template parameter to X (aka the curiously recurring
                  > > template pattern).
                  > >
                  > > Thanks,
                  > > john[/color]
                  >
                  > How about this:
                  >
                  > template <class DerivedTraits, class Derived>
                  > struct X
                  > {
                  > // typedef typename Derived::type type;
                  > typedef typename DerivedTraits:: type type;
                  > };
                  >
                  > struct YTraits {
                  > typedef int type;
                  > };
                  >
                  > struct Y : public YTraits, X<YTraits, Y>
                  > {
                  > // typedef int type;
                  > };
                  >
                  > Denis[/color]

                  In other words, I meant refactoring the derived class into two parts, the
                  first of which does not depend on X, then using it as above. Doing so breaks
                  the circular dependence of the original scheme, in which X gets parsed first,
                  attempting to look up names to be declared in Y, which hasn't been parsed
                  yet because it has X as a base. A bit of a prop to the compiler here.

                  Denis

                  Comment

                  • Sharad Kala

                    #10
                    Re: curiously recurring template pattern problem


                    "Chris Theis" <Christian.Thei s@nospam.cern.c h> wrote in message
                    news:c50c1e$mf3 $1@sunnews.cern .ch...[color=blue]
                    > "John Harrison" <john_andronicu s@hotmail.com> wrote in message
                    > news:c509lr$2nl 3hi$1@ID-196037.news.uni-berlin.de...[color=green]
                    > > The following code does not compile
                    > >[/color]
                    > [SNIP]
                    >
                    > There is a way to circumvent this (IMHO probably correct behavior) by using
                    > templates only instead of typedefs.
                    >
                    > template <class Derived, typename DerivedType>
                    > struct X
                    > {
                    > X() {};
                    > ~X() {};
                    > void test() { cout << typeid( type ).name() << endl; };
                    > typedef typename DerivedType type;[/color]

                    I don't think you need a typename here.
                    [color=blue]
                    > };
                    >
                    > template<typena me InternalType>
                    > struct Y : public X<Y, InternalType>[/color]

                    Isn't Y a class template? In that case writing public X<Y, InternalType> should
                    be an error.

                    -Sharad


                    Comment

                    • Sharad Kala

                      #11
                      Re: curiously recurring template pattern problem


                      "Chris Theis" <Christian.Thei s@nospam.cern.c h> wrote in message
                      news:c50c1e$mf3 $1@sunnews.cern .ch...[color=blue]
                      > "John Harrison" <john_andronicu s@hotmail.com> wrote in message
                      > news:c509lr$2nl 3hi$1@ID-196037.news.uni-berlin.de...[color=green]
                      > > The following code does not compile
                      > >[/color]
                      > [SNIP]
                      >
                      > There is a way to circumvent this (IMHO probably correct behavior) by using
                      > templates only instead of typedefs.
                      >
                      > template <class Derived, typename DerivedType>
                      > struct X
                      > {
                      > X() {};
                      > ~X() {};
                      > void test() { cout << typeid( type ).name() << endl; };
                      > typedef typename DerivedType type;[/color]

                      I don't think you need a typename here.
                      [color=blue]
                      > };
                      >
                      > template<typena me InternalType>
                      > struct Y : public X<Y, InternalType>[/color]

                      Isn't Y a class template? In that case writing public X<Y, InternalType> should
                      be an error.

                      -Sharad


                      Comment

                      • Sharad Kala

                        #12
                        Re: curiously recurring template pattern problem


                        "John Harrison" <john_andronicu s@hotmail.com> wrote in message
                        news:c509lr$2nl 3hi$1@ID-196037.news.uni-berlin.de...[color=blue]
                        > The following code does not compile
                        >[/color]
                        \> Can someone explain to my why this should be a problem? I'm presuming that[color=blue]
                        > this kind of construct is difficult or impossible to compile for some
                        > reason.[/color]

                        In CRTP even though the base class depends on the derived class, it cannot do so
                        in a way that requires the complete type of derived to be known to the base
                        class.

                        -Sharad


                        Comment

                        • Sharad Kala

                          #13
                          Re: curiously recurring template pattern problem


                          "John Harrison" <john_andronicu s@hotmail.com> wrote in message
                          news:c509lr$2nl 3hi$1@ID-196037.news.uni-berlin.de...[color=blue]
                          > The following code does not compile
                          >[/color]
                          \> Can someone explain to my why this should be a problem? I'm presuming that[color=blue]
                          > this kind of construct is difficult or impossible to compile for some
                          > reason.[/color]

                          In CRTP even though the base class depends on the derived class, it cannot do so
                          in a way that requires the complete type of derived to be known to the base
                          class.

                          -Sharad


                          Comment

                          • tom_usenet

                            #14
                            Re: curiously recurring template pattern problem

                            On Wed, 7 Apr 2004 08:12:59 +0100, "John Harrison"
                            <john_andronicu s@hotmail.com> wrote:
                            [color=blue]
                            >Secondly is there a way to achieve what I want, which is to let X know the
                            >definition of a type defined in any class derived from X, by passing the
                            >derived type as a template parameter to X (aka the curiously recurring
                            >template pattern).[/color]

                            This might help:

                            template <class Derived, class T>
                            struct X
                            {
                            typedef T type;
                            };

                            struct Y : public X<Y, int>
                            {
                            };

                            int main()
                            {
                            }

                            At what point does X need to know the type of "type" though? If it
                            isn't required by the definition of X, but only the definition of its
                            members, then you shouldn't have a problem. e.g.

                            template <class Derived>
                            struct X
                            {
                            void foo()
                            {
                            typedef typename Derived::type type;
                            //use type
                            }
                            };

                            struct Y : public X<Y>
                            {
                            typedef int type;
                            };


                            Tom
                            --
                            C++ FAQ: http://www.parashift.com/c++-faq-lite/
                            C FAQ: http://www.eskimo.com/~scs/C-faq/top.html

                            Comment

                            • tom_usenet

                              #15
                              Re: curiously recurring template pattern problem

                              On Wed, 7 Apr 2004 08:12:59 +0100, "John Harrison"
                              <john_andronicu s@hotmail.com> wrote:
                              [color=blue]
                              >Secondly is there a way to achieve what I want, which is to let X know the
                              >definition of a type defined in any class derived from X, by passing the
                              >derived type as a template parameter to X (aka the curiously recurring
                              >template pattern).[/color]

                              This might help:

                              template <class Derived, class T>
                              struct X
                              {
                              typedef T type;
                              };

                              struct Y : public X<Y, int>
                              {
                              };

                              int main()
                              {
                              }

                              At what point does X need to know the type of "type" though? If it
                              isn't required by the definition of X, but only the definition of its
                              members, then you shouldn't have a problem. e.g.

                              template <class Derived>
                              struct X
                              {
                              void foo()
                              {
                              typedef typename Derived::type type;
                              //use type
                              }
                              };

                              struct Y : public X<Y>
                              {
                              typedef int type;
                              };


                              Tom
                              --
                              C++ FAQ: http://www.parashift.com/c++-faq-lite/
                              C FAQ: http://www.eskimo.com/~scs/C-faq/top.html

                              Comment

                              Working...