Template class partial specialisation problem

Discussion in 'C++' started by Lionel B, Nov 3, 2004.

  1. Lionel B

    Lionel B Guest

    Greetings.

    The following code compiles ok and does what I'd expect it to do:

    [apologies for the lack of indentation... Google Groups 2 Beta bug
    reported]

    ---------- START CODE ----------

    // test.cpp

    #include <iostream>

    template <class T> struct A
    {
    A();
    };

    A<int>::A()
    {
    std::cout << "Template parameter is \"int\"" << '\n';
    }

    A<long>::A()
    {
    std::cout << "Template parameter is \"long\"" << '\n';
    }

    int main()
    {
    A<int> a1;
    A<long> a2;

    return 0;
    }

    ---------- END CODE ----------

    The program outputs:

    Template parameter is "int"
    Template parameter is "long"

    So far so good... now I would like to do the same, but there is a
    second template parameter and I only want to specialise on the first:

    ---------- START CODE ----------

    // test.cpp

    #include <iostream>

    template <class T, class R> struct A
    {
    A();
    };

    template <class R> A<int, R>::A() // line 10
    {
    std::cout << "First template parameter is \"int\"" << '\n';
    }

    template <class R> A<long, R>::A() // line 15
    {
    std::cout << "First template parameter is \"long\"" << '\n';
    }

    int main()
    {
    A<int, int> a1;
    A<long, int> a2;

    return 0;
    }

    ---------- END CODE ----------

    My compiler (gcc 3.3.3 cygwin special) throws this out with:

    g++ test.cpp -o test.exe
    test.cpp:10: error: parse error before `)' token
    test.cpp:15: error: parse error before `)' token

    I can't figure out quite what the syntax should be to specialise on the
    first template parameter only. It would seem that A<int, R>::A() is
    still a template function, but my compiler doesn't like the "obvious"
    definition:
    template <class R> A<int, R>::A()

    Any help appreciated,

    --
    Lionel B
     
    Lionel B, Nov 3, 2004
    #1
    1. Advertising

  2. Lionel B wrote:
    > Greetings.
    >
    > The following code compiles ok and does what I'd expect it to do:
    >
    > [apologies for the lack of indentation... Google Groups 2 Beta bug
    > reported]
    >
    > ---------- START CODE ----------
    >
    > // test.cpp
    >
    > #include <iostream>
    >
    > template <class T> struct A
    > {
    > A();
    > };
    >
    > A<int>::A()
    > {
    > std::cout << "Template parameter is \"int\"" << '\n';
    > }
    >
    > A<long>::A()
    > {
    > std::cout << "Template parameter is \"long\"" << '\n';
    > }
    >
    > int main()
    > {
    > A<int> a1;
    > A<long> a2;
    >
    > return 0;
    > }
    >
    > ---------- END CODE ----------
    >
    > The program outputs:
    >
    > Template parameter is "int"
    > Template parameter is "long"
    >
    > So far so good... now I would like to do the same, but there is a
    > second template parameter and I only want to specialise on the first:
    >
    > ---------- START CODE ----------
    >
    > // test.cpp
    >
    > #include <iostream>
    >
    > template <class T, class R> struct A
    > {
    > A();
    > };
    >
    > template <class R> A<int, R>::A() // line 10
    > {
    > std::cout << "First template parameter is \"int\"" << '\n';
    > }
    >
    > template <class R> A<long, R>::A() // line 15
    > {
    > std::cout << "First template parameter is \"long\"" << '\n';
    > }
    >
    > int main()
    > {
    > A<int, int> a1;
    > A<long, int> a2;
    >
    > return 0;
    > }
    >
    > ---------- END CODE ----------
    >
    > My compiler (gcc 3.3.3 cygwin special) throws this out with:
    >
    > g++ test.cpp -o test.exe
    > test.cpp:10: error: parse error before `)' token
    > test.cpp:15: error: parse error before `)' token
    >
    > I can't figure out quite what the syntax should be to specialise on the
    > first template parameter only. It would seem that A<int, R>::A() is
    > still a template function, but my compiler doesn't like the "obvious"
    > definition:
    > template <class R> A<int, R>::A()


    I believe to partially specialise a member, you need to partially
    specialise the class first. You need to add these lines before the
    member specialisations:

    template<class R> struct A<int,R> { A(); };
    template<class R> struct A<long,R> { A(); };

    Victor
     
    Victor Bazarov, Nov 3, 2004
    #2
    1. Advertising

  3. Lionel B

    Lionel B Guest

    Victor Bazarov wrote:
    > Lionel B wrote:


    /snip/

    > > I can't figure out quite what the syntax should be to specialise
    > > on the first template parameter only. It would seem that
    > > A<int, R>::A() is still a template function, but my compiler
    > > doesn't like the "obvious" definition:
    > > template <class R> A<int, R>::A()

    >
    > I believe to partially specialise a member, you need to partially
    > specialise the class first. You need to add these lines before the
    > member specialisations:
    >
    > template<class R> struct A<int,R> { A(); };
    > template<class R> struct A<long,R> { A(); };


    Cheers, Victor. But that leaves me with a problem; it seems then that I
    have to partially specialise *every member function* in the class.
    e.g.:

    ---------- START CODE ----------

    // test.cpp

    #include <iostream>

    template <class T, class R> struct A
    {
    A();
    void foo() {}
    };

    template<class R> struct A<int,R> {A();};
    template<class R> A<int, R>::A()
    {
    std::cout << "First template parameter is \"int\"" << '\n';
    }

    template<class R> struct A<long,R> {A();};
    template<class R> A<long, R>::A()
    {
    std::cout << "First template parameter is \"long\"" << '\n';
    }

    int main()
    {
    A<int, int> a1;
    A<long, int> a2;

    a1.foo();
    a2.foo();

    return 0;
    }

    ---------- END CODE ----------

    g++ test.cpp -o test.exe
    test.cpp: In function `int main()':
    test.cpp:28: error: `foo' undeclared (first use this function)
    test.cpp:28: error: (Each undeclared identifier is reported only once
    for each
    function it appears in.)

    Problem is my class has *many* member functions, but only a handful of
    them need to be partially specialised. Surely I shouldn't have to
    re-write identical code for every member function that does not need to
    be partially specialised?

    --
    Lionel B



    Now this is really not on for my class, as there is no way I
     
    Lionel B, Nov 3, 2004
    #3
  4. Lionel B wrote:
    > Victor Bazarov wrote:
    >
    >>Lionel B wrote:

    >
    >
    > /snip/
    >
    >
    >>>I can't figure out quite what the syntax should be to specialise
    >>>on the first template parameter only. It would seem that
    >>>A<int, R>::A() is still a template function, but my compiler
    >>>doesn't like the "obvious" definition:
    >>>template <class R> A<int, R>::A()

    >>
    >>I believe to partially specialise a member, you need to partially
    >>specialise the class first. You need to add these lines before the
    >>member specialisations:
    >>
    >>template<class R> struct A<int,R> { A(); };
    >>template<class R> struct A<long,R> { A(); };

    >
    >
    > Cheers, Victor. But that leaves me with a problem; it seems then that I
    > have to partially specialise *every member function* in the class.


    Why?

    > e.g.:
    >
    > ---------- START CODE ----------
    >
    > // test.cpp
    >
    > #include <iostream>
    >
    > template <class T, class R> struct A
    > {
    > A();
    > void foo() {}
    > };
    >
    > template<class R> struct A<int,R> {A();};
    > template<class R> A<int, R>::A()
    > {
    > std::cout << "First template parameter is \"int\"" << '\n';
    > }
    >
    > template<class R> struct A<long,R> {A();};
    > template<class R> A<long, R>::A()
    > {
    > std::cout << "First template parameter is \"long\"" << '\n';
    > }
    >
    > int main()
    > {
    > A<int, int> a1;
    > A<long, int> a2;
    >
    > a1.foo();
    > a2.foo();
    >
    > return 0;
    > }
    >
    > ---------- END CODE ----------
    >
    > g++ test.cpp -o test.exe
    > test.cpp: In function `int main()':
    > test.cpp:28: error: `foo' undeclared (first use this function)
    > test.cpp:28: error: (Each undeclared identifier is reported only once
    > for each
    > function it appears in.)
    >
    > Problem is my class has *many* member functions, but only a handful of
    > them need to be partially specialised. Surely I shouldn't have to
    > re-write identical code for every member function that does not need to
    > be partially specialised?


    By partial specialisation of a template class you create another template.
    You're responsible for its contents. If you say that it's not going to
    have the 'foo' member, it's not going to have the 'foo' member. But if
    you try to use the 'foo' member, you get an error. You're basically
    contradicting yourself here. OOH you say, here is a special variation of
    my A template, see? It doesn't have a foo function. Then you say, no I
    do want it to have a foo function. So, which is it? It's a rhetorical
    question...

    One thing you should remember, there is no partial specialisation of
    function templates. None. Not allowed. That basically means no partial
    specialisations of member functions, either, by themselves. What you are
    allowed to create is a full specialisation of a member of another class
    template, who just happens to be a partial specialisation of your original
    class template.

    Such is life.

    >
    > --
    > Lionel B
    >
    >
    >
    > Now this is really not on for my class, as there is no way I


    Huh? Sorry, I can't say I understand what you're trying to say here.
     
    Victor Bazarov, Nov 3, 2004
    #4
  5. Lionel B

    Lionel B Guest

    Victor Bazarov wrote:
    > Lionel B wrote:
    > > Victor Bazarov wrote:
    > >
    > >>Lionel B wrote:

    > >
    > > /snip/
    > >
    > >>>I can't figure out quite what the syntax should
    > >>>be to specialise on the first template parameter
    > >>>only. It would seem that A<int, R>::A() is still
    > >>>a template function, but my compiler doesn't like
    > >>>the "obvious" definition:
    > >>>template <class R> A<int, R>::A()
    > >>
    > >>I believe to partially specialise a member, you need
    > >>to partially specialise the class first. You need to
    > >>add these lines before the member specialisations:
    > >>
    > >>template<class R> struct A<int,R> { A(); };
    > >>template<class R> struct A<long,R> { A(); };

    > >
    > > Cheers, Victor. But that leaves me with a problem; it
    > > seems then that I have to partially specialise *every
    > > member function* in the class.

    >
    > Why?


    Read on.

    /snip/

    > > Problem is my class has *many* member functions, but only
    > > a handful of them need to be partially specialised. Surely
    > > I shouldn't have to re-write identical code for every member
    > > function that does not need to be partially specialised?

    >
    > By partial specialisation of a template class you create another
    > template. You're responsible for its contents. If you say that
    > it's not going to have the 'foo' member, it's not going to have
    > the 'foo' member. But if you try to use the 'foo' member, you
    > get an error.


    What I would really like is that if a member function - foo, say - is
    not explicitly (partially) specialised, then the definition of the
    un-specialised foo member from the un-specialised template class is
    picked up. This works perfectly well with full specialisation:

    ---------- BEGIN CODE ----------

    #include <iostream>

    template <class T> struct A
    {
    A();
    void foo()
    {
    std::cout << "This is foo" << '\n';
    }
    };

    A<int>::A()
    {
    std::cout << "Template parameter is \"int\"" << '\n';
    }

    A<long>::A()
    {
    std::cout << "Template parameter is \"long\"" << '\n';
    }

    int main()
    {
    A<int> a1;
    A<long> a2;

    a1.foo();
    a2.foo();

    return 0;
    }

    ---------- END CODE ----------

    works perfectly well. Output:

    Template parameter is "int"
    Template parameter is "long"
    This is foo
    This is foo

    Here foo is simply picked up from its definition in the the
    un-specialised template class. Now I honestly don't see why this
    couldn't be the case for partial specialisation (evidently it isn't).

    To my mind this renders partial specialisation less than useful. If I'm
    going to have to write different definitions for every function of a
    partial specialisation of a template class, I may as well be done with
    it and write separate template classes for each specialisation!

    /snip/

    > One thing you should remember, there is no partial specialisation
    > of function templates. None. Not allowed. That basically means
    > no partial specialisations of member functions, either, by
    > themselves.


    Yup. That's precisely what I want... I suppose there must be a good
    reason for this, but I can't see it. As I say, it seems to work ok for
    full specialisation.

    > What you are
    > allowed to create is a full specialisation of a member of another
    > class template, who just happens to be a partial specialisation of
    > your original class template.


    Not sure I follow you here.

    > > Now this is really not on for my class, as there is no way I

    >
    > Huh? Sorry, I can't say I understand what you're trying to say here.

    Me neither. Editing glitch.

    --
    Lionel B
     
    Lionel B, Nov 3, 2004
    #5
  6. Lionel B wrote:
    > [...]
    > To my mind this renders partial specialisation less than useful. If I'm
    > going to have to write different definitions for every function of a
    > partial specialisation of a template class, I may as well be done with
    > it and write separate template classes for each specialisation!


    But that is what you essentially do when you partially specialise a class
    template. You _essentially_ create another template. Sort of.

    >>One thing you should remember, there is no partial specialisation
    >>of function templates. None. Not allowed. That basically means
    >>no partial specialisations of member functions, either, by
    >>themselves.

    >
    >
    > Yup. That's precisely what I want... I suppose there must be a good
    > reason for this, but I can't see it. As I say, it seems to work ok for
    > full specialisation.


    See "C++ Templates" by Vandevoorde and Josuttis, section 13.7. I am too
    lazy to re-type it all here.

    >>What you are
    >>allowed to create is a full specialisation of a member of another
    >>class template, who just happens to be a partial specialisation of
    >>your original class template.

    >
    >
    > Not sure I follow you here.


    I am not sure I follow myself. Never mind. Get the Vandevoorde/Josuttis
    book and many things are going to be clearer.

    V
     
    Victor Bazarov, Nov 3, 2004
    #6
  7. Lionel B

    Andre Dajd Guest

    "Lionel B" <> wrote in message news:<>...
    > Greetings.


    <snip>

    You may solve your issues by combining templates with inheritance.
    You write one (or many) base template class(es) and then subclass from
    them with reduced set of template parameters. This will pull all
    virtuals form the base which will be automatically specialized, but
    which you will still be able to overwrite.

    This will not always work, precisely because ALL base class function
    will be specialized in this approach (following standard instantiation
    rules), which may result in some illegal code being generated. That's
    why one may need to finer slice the superclass into several classes.

    Also, this will work only when the context will allow you to use the
    inherited methods polymorphically. Eg, it will not work in
    constructors.

    Back to Earth, your example could mutate into something like this:

    /******/
    #include <iostream>
    #include <string>

    // need these (or comparable) functions that implement static
    polymorphism
    // because constructors can only be statically polymorphic
    template<typename _T>
    static std::string const&
    TypeToString();

    template<>
    static std::string const&
    TypeToString<int>()
    {
    static std::string const ret = std::string("int");
    return ret;
    }

    template<>
    static std::string const&
    TypeToString<long>()
    {
    static std::string const ret = std::string("long");
    return ret;
    }

    template<>
    static std::string const&
    TypeToString<double>()
    {
    static std::string const ret = std::string("double");
    return ret;
    }

    // now the main thing stars
    template<typename _First, typename _Second>
    struct Base
    {
    typedef _First First;
    typedef _Second Second;

    virtual ~Base() {}

    Base() { printFirstTemplateParameter(); }

    void
    printFirstTemplateParameter() { std::cout<<"First parameter type:
    "<<TypeToString<First>()<<std::endl; }

    virtual void
    someOtherFunction() { std::cout<<"UNIX: dont know what to
    do!"<<std::endl; }
    };

    template<typename T>
    struct BaseSecedToInt
    : public Base<int, T>
    {
    void
    someOtherFunction() { std::cout<<"Windoze: dont know what to
    do!"<<std::endl; }
    };

    template<typename T>
    struct BaseSecedToLong
    : public Base<long, T>
    {
    void
    someOtherFunction() { std::cout<<"OSX: dont know what to
    do!"<<std::endl; }
    };


    int main(int argc, char *argv[])
    {
    Base<double, double> b;
    b.someOtherFunction();

    BaseSecedToInt<double> bi;
    bi.someOtherFunction();

    BaseSecedToLong<double> bl;
    bl.someOtherFunction();

    return 0;
    }
     
    Andre Dajd, Nov 4, 2004
    #7
  8. Lionel B

    Lionel B Guest

    Andre Dajd wrote:
    > "Lionel B" <> wrote in message

    news:<>...
    > > Greetings.

    >
    > <snip>
    >
    > You may solve your issues by combining templates with
    > inheritance. You write one (or many) base template class(es)
    > and then subclass from them with reduced set of template parameters.
    > This will pull allvirtuals form the base which will be automatically
    > specialized, but which you will still be able to overwrite.


    I had thought of trying something like that (although from what you
    point out below it would not neccesarilly have worked, I suspect) and
    rejected it on the grounds of: (a) my class is very low-level and
    supposed to be super-efficient - could not afford the overhead of
    virtual functions - and (b) it would entail horrifically obscure code,
    as your example amply demonstrates ;)

    > This will not always work, precisely because ALL base class
    > function will be specialized in this approach (following standard
    > instantiation rules), which may result in some illegal code being
    > generated. That's why one may need to finer slice the superclass
    > into several classes.


    This would probably be a nightmare in my case.

    > Also, this will work only when the context will allow you to use
    > the inherited methods polymorphically. Eg, it will not work in
    > constructors.


    [...]

    Thanks,

    --
    Lionel B
     
    Lionel B, Nov 4, 2004
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Tim Clacy
    Replies:
    12
    Views:
    628
    Dan W.
    Dec 3, 2003
  2. Jules
    Replies:
    6
    Views:
    464
    Jules
    Aug 18, 2005
  3. =?windows-1252?Q?Erik_Wikstr=F6m?=

    Templates, policy-based design, partial specialisation and pointers

    =?windows-1252?Q?Erik_Wikstr=F6m?=, Nov 5, 2005, in forum: C++
    Replies:
    4
    Views:
    293
    =?windows-1252?Q?Erik_Wikstr=F6m?=
    Nov 5, 2005
  4. Martin Gernhard
    Replies:
    2
    Views:
    367
    Martin Gernhard
    Nov 16, 2005
  5. Adrian Hawryluk

    Template class partial specialisation

    Adrian Hawryluk, Mar 19, 2007, in forum: C++
    Replies:
    2
    Views:
    334
    Adrian Hawryluk
    Mar 19, 2007
Loading...

Share This Page