Re: Circular Class Template Friendship

From: Victor Bazarov (v.Abazarov_at_comAcast.net)
Date: 07/24/04


Date: Sat, 24 Jul 2004 16:59:19 GMT


"Thomas Matthews" <Thomas_MatthewsSpamBotsSuck@sbcglobal.net> wrote...
> I am converting my table and record classes into templates.
> My issue is the syntax of declaring a friend class within
> the template. I have searched the C++ FAQ Lite (web),
> the C++ newsgroups, "Thinking In C++" to no avail.
>
>
> Background
> ----------
> My table is a collection of <integer, string> pairs, in
> which the string is a fixed width that is specialized.
> One specialization of the table may have a 32 length
> string and another 64. The table is also a Singleton.
>
> The record class is of the form <integer, string>.
> The integer portion, the primary key, is hidden from
> public usage, so that the class behaves like a string.
> When the class is written as a field of a record, the
> integer portion will be written out.
>
> Part of the interface is for the table to be a friend
> of the record. This allows the table to set the primary
> key without giving access or knowledge of the primary
> key to the general public.
>
>
> The Code
> ---------
> Here is my code:
> // File Name_Id_Table.hpp
>
> template <typename Record_Class,
> const char * TABLE_NAME>
> class Name_Id_Table
> {
> //...
> public:
> void load_from_table(Record_Class& rc)
> {
> rc.id = get_id_from_table();
> rc.name = get_name_from_table();
> }
> };
>
> // File Name_Id.hpp
> #include <string>
> using std::string

Ugh! Yuck!!! Never put a using declaration into a global scope in
a header. NEVER! There is no reason for it to be there. If you
are so inclined to save some typing and use 'string' instead of
'std::string' in your class definition, put the 'using' there, inside
that class definition. Hide your 'using's as deep as possible.

>
> template <int MAX_STRING_WIDTH>
> class Name_Id
> {
> // ...
>
> /* The following line is what I need help with */
> template <> friend class<Name_ID, ????> Name_Id_Table;

What are you trying to accomplish? All possible Name_Id_Table
instantiations with the same Name_ID should be friends or only
the one that has a particular TABLE_NAME?

At this point, it is still possible to have Name_Id_Table template
specialised on the same Name_Id class, but with different table
names. There is nothing in your code that prevents that.

So, do you want a particular fully specialised Name_Id_Table to
be a friend? Then you have to give the address of a constant
character here. Which one? You decide. The easiest solution
would be to give Name_Id an extra argument and pass it along to
the friend class declaration.

>
> private:
> int id;
> string name;
> };
>
>
> // File main.cpp
> #include "Name_Id_Table.hpp"
> #include "Name_Id.hpp"
>
> const char * TITLE_TABLE_NAME = "Titles";

No, that has to be 'extern'.

>
> /* Here is another issue I'm having problems with.
> * I want to declare the types but am having syntax
> * issues.

WHAT syntax issues?

> */
> typedef Name_Id<64> Title;
> typedef Name_Id_Table<Title, TITLE_TABLE_NAME> Title_Table;
>
> int main(void)
> {
> Title t;
> Title_Table table;
>
> table.load_from_table(t);
>
> return EXIT_SUCCESS;
> }
>
>
>
> In the database, I will have three Name-ID tables:
> Title, Author, Publisher. The string widths will
> differ and they will have different table names.

You can create a templated "table of widths" and only worry
about passing the name to your 'Name_Id' template and to the
'Name_Id_Table' template:
---------------------------------------------------------
template<const char* name> struct Name_Id_Aux_Info { enum { MaxWidth }; };
template<typename T, const char* name> class Name_Id_Table;

template<const char* name> class Name_Id {
    enum { MAX_STRING_WIDTH =
              Name_Id_Aux_Info<name>::MaxWidth };

    int foo() { return 42; } // private
    friend class Name_Id_Table<Name_Id, name>;
};

template<typename T, const char* name> class Name_Id_Table
{
public:
    int bar(T& t) { return t.foo(); }
};

extern const char TITLE[] = "Title";
extern const char AUTHOR[] = "Author";
extern const char PUBLISHER[] = "Publisher";

template<> struct Name_Id_Aux_Info<TITLE> { enum { MaxWidth = 32 }; };
template<> struct Name_Id_Aux_Info<AUTHOR> { enum { MaxWidth = 64 }; };
template<> struct Name_Id_Aux_Info<PUBLISHER> { enum { MaxWidth = 96 }; };

typedef Name_Id<TITLE> id_Title;
typedef Name_Id_Table<id_Title, TITLE> id_Title_Table;

int main()
{
    id_Title idt;
    id_Title_Table idtt;

    idtt.bar(idt);

    return 0;
}

> Otherwise they have the same functionality. Each
> table is a singleton; the Title table will not
> contain author or publisher entries. Similarly
> with Author and Publisher tables.

If you tie them by the name only, you have a chance, I believe.



Relevant Pages

  • Re: Template friendship to nested template class
    ... friend struct INNER; ... Probably you are missing an EXTRA template to declare ... I think it's because the name referred to in a 'friend' declaration is looked up to exist at the namespace scope. ...
    (microsoft.public.vc.language)
  • Re: friend class in template
    ... This template takes 3 type parameters, the first of which is named ... The friend declaration attempts to declare the class ... the friend declaration doesn't do what the author apparently ... thought it would do (at least not on a conforming compiler). ...
    (microsoft.public.vc.language)
  • Re: Class templates and friend function templates
    ... > expected the friend declaration to resolve to: ... > as a friend of C. ... The confusion stems from the expectation that function ... template instantiation is similar to class template ...
    (microsoft.public.vc.language)
  • Re: OK in Visual C++6.0 but not in Visual C++ .NET 2003?
    ... it's a quirk of friend declarations. ... declaration, if no matching function is already visible, then a suitable ... template unless the friend declaration names a template (template ... friend void f).. ...
    (microsoft.public.dotnet.languages.vc)
  • Re: Errors in VC program with gdiplus
    ... template argument list ... : see declaration of 'iterator' ...
    (microsoft.public.vc.mfc)

Loading