calling generic template function from template specialization

Discussion in 'C++' started by johanatan, Feb 18, 2008.

  1. johanatan

    johanatan Guest

    I have two functions that are nearly identical (one validates a row
    and one validates a table). Since a table is open-ended (i.e., can
    have infinite rows) but a row is finite, there is one addtional line
    of code in the ValidateRow func which asserts that the row data has
    the appropriate number of cells.

    I would like to make these a template function with a specialization
    for the row that asserts the one extra condition and then calls the
    generic template function. Is this possible?

    Thanks,
    Jonathan
     
    johanatan, Feb 18, 2008
    #1
    1. Advertising

  2. johanatan

    Jeff Schwab Guest

    johanatan wrote:
    johanatan wrote:
    > I have two functions that are nearly identical (one validates a row
    > and one validates a table). Since a table is open-ended (i.e., can
    > have infinite rows) but a row is finite, there is one addtional line
    > of code in the ValidateRow func which asserts that the row data has
    > the appropriate number of cells.
    >
    > I would like to make these a template function with a specialization
    > for the row that asserts the one extra condition and then calls the
    > generic template function. Is this possible?
    >
    > Thanks,
    > Jonathan


    > I have two functions that are nearly identical (one validates a row
    > and one validates a table). Since a table is open-ended (i.e., can
    > have infinite rows) but a row is finite, there is one addtional line
    > of code in the ValidateRow func which asserts that the row data has
    > the appropriate number of cells.
    >
    > I would like to make these a template function with a specialization
    > for the row that asserts the one extra condition and then calls the
    > generic template function. Is this possible?


    Yes, but you probably want an overload rather than a specialization.

    It sounds like the code to validate a row is identical (except for the
    assertion) to the code that validates a table. Is this correct? If so,
    you can do something like:

    #include <cassert>
    #include <cstdlib>
    #include <string>
    #include <vector>

    std::size_t const row_size = 42;

    typedef std::string cell_type;
    typedef std::vector<cell_type> row_type;
    typedef std::vector<row_type> table_type;

    /* Works for tables and rows. */
    template<typename T>
    void validate(T const& t) {
    // ...
    }

    void validate(row_type const& row) {
    assert(row.size() == row_size);
    validate<row_type>(row);
    }

    int main() {
    row_type row(row_size );
    table_type table;

    table.push_back(row);

    /* Invokes an instantiation of the template. */
    validate(table);

    /* Invokes the row-specific overload, then
    * an instantiation of the template. */
    validate(row);
    }


    If you know the row's size at compile time, you might want to replace
    the row class with a template, so that the size can be a template parameter.
     
    Jeff Schwab, Feb 18, 2008
    #2
    1. Advertising

  3. johanatan

    johanatan Guest

    On Feb 18, 3:54 pm, Jeff Schwab <> wrote:
    > johanatan wrote:
    > johanatan wrote:
    > > I have two functions that are nearly identical (one validates a row
    > > and one validates a table).  Since a table is open-ended (i.e., can
    > > have infinite rows) but a row is finite, there is one addtional line
    > > of code in the ValidateRow func which asserts that the row data has
    > > the appropriate number of cells.

    >
    > > I would like to make these a template function with a specialization
    > > for the row that asserts the one extra condition and then calls the
    > > generic template function.  Is this possible?

    >
    > > Thanks,
    > > Jonathan
    > > I have two functions that are nearly identical (one validates a row
    > > and one validates a table).  Since a table is open-ended (i.e., can
    > > have infinite rows) but a row is finite, there is one addtional line
    > > of code in the ValidateRow func which asserts that the row data has
    > > the appropriate number of cells.

    >
    > > I would like to make these a template function with a specialization
    > > for the row that asserts the one extra condition and then calls the
    > > generic template function.  Is this possible?

    >
    > Yes, but you probably want an overload rather than a specialization.
    >
    > It sounds like the code to validate a row is identical (except for the
    > assertion) to the code that validates a table.  Is this correct?  If so,
    > you can do something like:
    >
    >      #include <cassert>
    >      #include <cstdlib>
    >      #include <string>
    >      #include <vector>
    >
    >      std::size_t const row_size = 42;
    >
    >      typedef std::string cell_type;
    >      typedef std::vector<cell_type> row_type;
    >      typedef std::vector<row_type> table_type;
    >
    >      /* Works for tables and rows. */
    >      template<typename T>
    >      void validate(T const& t) {
    >          // ...
    >      }
    >
    >      void validate(row_type const& row) {
    >          assert(row.size() == row_size);
    >          validate<row_type>(row);
    >      }
    >
    >      int main() {
    >          row_type row(row_size );
    >          table_type table;
    >
    >          table.push_back(row);
    >
    >          /* Invokes an instantiation of the template. */
    >          validate(table);
    >
    >          /* Invokes the row-specific overload, then
    >           * an instantiation of the template. */
    >          validate(row);
    >      }
    >
    > If you know the row's size at compile time, you might want to replace
    > the row class with a template, so that the size can be a template parameter.- Hide quoted text -
    >
    > - Show quoted text -


    Ahh. Hadn't thought of mixing overloads and templates. I was
    thinking that the validate(row_type) would have to also be a template
    (specialization).

    As for the size template param-- won't be necessary as both validates
    are members of a class that already knows the row size.

    Thanks!
    --Jonathan
     
    johanatan, Feb 18, 2008
    #3
  4. johanatan

    johanatan Guest

    On Feb 18, 3:54 pm, Jeff Schwab <> wrote:
    > johanatan wrote:
    > johanatan wrote:
    > > I have two functions that are nearly identical (one validates a row
    > > and one validates a table).  Since a table is open-ended (i.e., can
    > > have infinite rows) but a row is finite, there is one addtional line
    > > of code in the ValidateRow func which asserts that the row data has
    > > the appropriate number of cells.

    >
    > > I would like to make these a template function with a specialization
    > > for the row that asserts the one extra condition and then calls the
    > > generic template function.  Is this possible?

    >
    > > Thanks,
    > > Jonathan
    > > I have two functions that are nearly identical (one validates a row
    > > and one validates a table).  Since a table is open-ended (i.e., can
    > > have infinite rows) but a row is finite, there is one addtional line
    > > of code in the ValidateRow func which asserts that the row data has
    > > the appropriate number of cells.

    >
    > > I would like to make these a template function with a specialization
    > > for the row that asserts the one extra condition and then calls the
    > > generic template function.  Is this possible?

    >
    > Yes, but you probably want an overload rather than a specialization.
    >
    > It sounds like the code to validate a row is identical (except for the
    > assertion) to the code that validates a table.  Is this correct?  If so,
    > you can do something like:
    >
    >      #include <cassert>
    >      #include <cstdlib>
    >      #include <string>
    >      #include <vector>
    >
    >      std::size_t const row_size = 42;
    >
    >      typedef std::string cell_type;
    >      typedef std::vector<cell_type> row_type;
    >      typedef std::vector<row_type> table_type;
    >
    >      /* Works for tables and rows. */
    >      template<typename T>
    >      void validate(T const& t) {
    >          // ...
    >      }
    >
    >      void validate(row_type const& row) {
    >          assert(row.size() == row_size);
    >          validate<row_type>(row);
    >      }
    >
    >      int main() {
    >          row_type row(row_size );
    >          table_type table;
    >
    >          table.push_back(row);
    >
    >          /* Invokes an instantiation of the template. */
    >          validate(table);
    >
    >          /* Invokes the row-specific overload, then
    >           * an instantiation of the template. */
    >          validate(row);
    >      }
    >
    > If you know the row's size at compile time, you might want to replace
    > the row class with a template, so that the size can be a template parameter.


    Though it isn't required in this case, just out of curiosity, is it
    possible to do what I originally asked?
     
    johanatan, Feb 19, 2008
    #4
  5. johanatan

    johanatan Guest

    On Feb 18, 3:54 pm, Jeff Schwab <> wrote:

    >
    > If you know the row's size at compile time, you might want to replace
    > the row class with a template, so that the size can be a template parameter.


    And actually, yea, it would be best to move some of the metadata to
    compile time rather than run time. Thanks for the suggestion.
     
    johanatan, Feb 19, 2008
    #5
  6. johanatan

    Jeff Schwab Guest

    johanatan wrote:
    > On Feb 18, 3:54 pm, Jeff Schwab <> wrote:
    >> johanatan wrote:
    >> johanatan wrote:
    >>> I have two functions that are nearly identical (one validates a row
    >>> and one validates a table). Since a table is open-ended (i.e., can
    >>> have infinite rows) but a row is finite, there is one addtional line
    >>> of code in the ValidateRow func which asserts that the row data has
    >>> the appropriate number of cells.
    >>> I would like to make these a template function with a specialization
    >>> for the row that asserts the one extra condition and then calls the
    >>> generic template function. Is this possible?
    >>> Thanks,
    >>> Jonathan
    >>> I have two functions that are nearly identical (one validates a row
    >>> and one validates a table). Since a table is open-ended (i.e., can
    >>> have infinite rows) but a row is finite, there is one addtional line
    >>> of code in the ValidateRow func which asserts that the row data has
    >>> the appropriate number of cells.
    >>> I would like to make these a template function with a specialization
    >>> for the row that asserts the one extra condition and then calls the
    >>> generic template function. Is this possible?

    >> Yes, but you probably want an overload rather than a specialization.
    >>
    >> It sounds like the code to validate a row is identical (except for the
    >> assertion) to the code that validates a table. Is this correct? If so,
    >> you can do something like:
    >>
    >> #include <cassert>
    >> #include <cstdlib>
    >> #include <string>
    >> #include <vector>
    >>
    >> std::size_t const row_size = 42;
    >>
    >> typedef std::string cell_type;
    >> typedef std::vector<cell_type> row_type;
    >> typedef std::vector<row_type> table_type;
    >>
    >> /* Works for tables and rows. */
    >> template<typename T>
    >> void validate(T const& t) {
    >> // ...
    >> }
    >>
    >> void validate(row_type const& row) {
    >> assert(row.size() == row_size);
    >> validate<row_type>(row);
    >> }
    >>
    >> int main() {
    >> row_type row(row_size );
    >> table_type table;
    >>
    >> table.push_back(row);
    >>
    >> /* Invokes an instantiation of the template. */
    >> validate(table);
    >>
    >> /* Invokes the row-specific overload, then
    >> * an instantiation of the template. */
    >> validate(row);
    >> }
    >>
    >> If you know the row's size at compile time, you might want to replace
    >> the row class with a template, so that the size can be a template parameter.

    >
    > Though it isn't required in this case, just out of curiosity, is it
    > possible to do what I originally asked?


    Sort of. You still need two version of the function (one that asserts,
    and another that doesn't); once you've specialized the template, though,
    there's no way to un-specialize it. One work-around is to have an
    "inner" (implementation) template invoked by the outer (interface) template.

    template<typename T>
    void validate_impl(T const& t) {
    // ...
    }

    /* Works for tables and rows. */
    template<typename T>
    void validate(T const& t) {
    validate_impl(t);
    }

    template<>
    void validate(row_type const& row) {
    assert(row.size() == row_size);
    validate_impl(row);
    }
     
    Jeff Schwab, Feb 19, 2008
    #6
  7. johanatan

    James Kanze Guest

    On Feb 18, 11:57 pm, johanatan <> wrote:
    > I have two functions that are nearly identical (one validates
    > a row and one validates a table). Since a table is open-ended
    > (i.e., can have infinite rows) but a row is finite, there is
    > one addtional line of code in the ValidateRow func which
    > asserts that the row data has the appropriate number of cells.


    > I would like to make these a template function with a
    > specialization for the row that asserts the one extra
    > condition and then calls the generic template function. Is
    > this possible?


    The usual solution would be to use traits. Something like:

    template< typename T >
    struct AdditionalValidations
    {
    static bool isOk( T const& ) { return true ; }
    } ;

    template<>
    struct AdditionalValidations< Row >
    {
    static bool isOk( Row const& row )
    {
    return row.size() == whatever ;
    }
    } ;

    In your template function, you would add code like:

    if ( theUsualValidations( obj )
    && AdditionalValidations< T >::isOk( obj ) {
    // error handling...
    }

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Feb 19, 2008
    #7
    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. Dave
    Replies:
    4
    Views:
    7,775
    pdixtl
    Jun 4, 2010
  2. Ruben Campos
    Replies:
    3
    Views:
    6,533
  3. Joseph Turian
    Replies:
    4
    Views:
    622
    John Carson
    Mar 20, 2006
  4. Joseph Turian
    Replies:
    2
    Views:
    494
  5. Replies:
    2
    Views:
    359
Loading...

Share This Page