473,834 Members | 2,001 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Meta class programming question

I have a class that is basicaly duplicated throughout several files with
only members names changing according to the class name yet with virtually
the exact same coding going on.

e.g.

class A
{
std::vector<B*> Bs;
public:
A() { blah; }

void SomeFunc_A() {blah blah blah};
}

class A
{
std::vector<C*> Cs;
public:
B() { blah; }

void SomeFunc_B() {blah blah blah};
}

and eventually one of the classes is a "terminal" in the sense it does not
continue the same abstract recursive process. My question is, is there any
way to automate this process? It seems I cannot use templates because I
cannot generate the proper method names are derived from the name of the
class?

i.e., I can't do something like

Metaclass template <class name, class subname>
class name
{
std::vector<sub name *> subname's';
public:
name() {blah}

void SomeFunc_@'name ' () { blah blah blah}
}

where say the 's' is appended to the subname literal and the @ appends the
string to the someFunc literal...

then I could do something like

Metaclass<A, B> and it produces the class Agiving above and Metaclass<B,C>
would produce B.
The reason I do this is because right now I have 7 files in my project that
all are virtually exactly the same as just 1(and how I got them was basicaly
using find and replace 3 times to turn the class into a "new" one that is
virtually identical with the other(excep ofcourse the coding is actualy the
same with different literals)).

My question is, is there any way in C++ to do something like this(I know my
code is not valid C++ code above but just giving some example). I just need
to generate a class from a meta class that also can change the method's
names that will be based on the name of the class.

Actually I will give a more concrete example that I actually kinda use in my
program:

class Score : public Base
{
public:
std::vector<Sta ff> Staffs;
int NumStaffs() { return (int)Staffs.siz e(); }
}

class Staff : public Base
{
public:
std::vector<Bar > Bars;
int NumBars() { return (int)Bars.size( ); }
}

class Bar : public Base
{
private:
public:
}

class Base
{
public:
std::vector<Pro perty> Properties;
int NumProperties() { return (int)Properties .size(); }
}

class Property
{
private:
public:
}

and I would want to access methods like:

Score.NumStaffs ();
Score.Staffs[0].NumBars();
etc...

I know I could make some general template where all methods across the
different classes would have the same name so I might have

Score.NumObject s(); which would return the number of objects in in the
vector in that object and(Staffs in this cass)
Score.Objects[0].NumObjects(); would return same as above but for the Bars.

The problem with this is I only need the recursiveness for about 5 classes
and that I want the naming to follow the modelling I'm using(modeling of
Score->Staff->Bar->Notes of music) else it might be confusing to remeber

Score.Objects[0].Objects[3].NumObjects(); is refering to

So thats the idea... as you can see most the classes are exactly the same
except for the naming of functions. I do see a problem now with my example
above about just adding 's' to the end... I wouldn't want Propertys but
Properties so there would have to be a way of creating logical english
literal names(i.e., replace ending y with ies when adding s), etc...

Anything that can do something like this out there? (would save me a lot of
work of having to to mess with 7 files that are identical except for naming
and potential other problems)

Jon

Sep 7 '05
21 4091

Jon Slaughter wrote:
the code I'm trying to get to work is

template <class content, bool t = true>
class RDES
{
private:
std::vector<con tent *> _content;
public:
#if t
RDES2 Properties;
#endif


That doesn't do what you think (or hope) it does. The preprocessor
does not understand templates. You're hoping that the above three
lines will be prepocessed into "RDES2 Properties" if t is true and into
nothing if t is false. But in reality, the preprocessor has no clue
that t is a template parameter and rather simply sees the t as an
undefined identifier, which it replaces with 0. Thus, the #if
expression always evaluates to false, so RDES2 Properties line is never
included by the preprocessor. Only AFTER the proprocessor is finished
does the compiler parse your template.

Best regards,

Tom

Sep 8 '05 #11

"Thomas Tutone" <Th***********@ yahoo.com> wrote in message
news:11******** *************@g 49g2000cwa.goog legroups.com...

Jon Slaughter wrote:
the code I'm trying to get to work is

template <class content, bool t = true>
class RDES
{
private:
std::vector<con tent *> _content;
public:
#if t
RDES2 Properties;
#endif


That doesn't do what you think (or hope) it does. The preprocessor
does not understand templates. You're hoping that the above three
lines will be prepocessed into "RDES2 Properties" if t is true and into
nothing if t is false. But in reality, the preprocessor has no clue
that t is a template parameter and rather simply sees the t as an
undefined identifier, which it replaces with 0. Thus, the #if
expression always evaluates to false, so RDES2 Properties line is never
included by the preprocessor. Only AFTER the proprocessor is finished
does the compiler parse your template.

Best regards,

Tom


yeah, I see. The preprocessor will parse the file first and do its thing and
sence the template is not part of the preprocessor the #if statement just
gets removed from it. Ofcourse I think even if it did work I'd still get
the error about using a class inside its definition.

So my question is: Is there any way to use a class inside itself? Maybe a
pointer but I'd be wasting a pointer in those cases where I don't use the
class(as when the class itself is representing a properties class).
Best way I can put it into words if I'm trying to use one template to
represent two classes that are slightly different. Its sorta polymorphism
that isn't exact or maybe a "dynamic template" or something like that. Maybe
there is some more advanced ways that I'm not awear of to do this sorta
thing(after all, I'm kinda flying by the seat of my pants at the moment and
if I could just get pointed in the right direction then I might be able to
get a grip on it)?

Thanks,

Jon
Sep 8 '05 #12
Jon Slaughter wrote:
So my question is: Is there any way to use a class inside itself? Maybe a
pointer but I'd be wasting a pointer in those cases where I don't use the
class(as when the class itself is representing a properties class).
Best way I can put it into words if I'm trying to use one template to
represent two classes that are slightly different. Its sorta polymorphism
that isn't exact or maybe a "dynamic template" or something like that. Maybe
there is some more advanced ways that I'm not awear of to do this sorta
thing(after all, I'm kinda flying by the seat of my pants at the moment and
if I could just get pointed in the right direction then I might be able to
get a grip on it)?


You will need to forward declare the class and use pointers, you can't
have a class as a direct member of itself, because the size cannot be
determined (it's recursive).

Have you thought about having something like the adaptor pattern against
a common implementation:

/* Common Implementation */
class MyClassImpl {
public:
void SomeFunc() {
// foo
}
};

/* Adaption 1 */
class MyClass1 {
MyClassImpl impl_;
public:
inline void SomeFunc_MyClas s1() {
impl_.SomeFunc( );
}
};

/* Adaption 2 */
class MyClass2 {
MyClassImpl impl_;
public:
inline void SomeFunc_MyClas s2() {
impl_.SomeFunc( );
}
};

So that you only have to maintain a very thin interface, not the
implementation?

You could also use inheritance, but in that case, probably MyClassImpl
will be abstract, and you'd probably want to inherit privately (or
protected).

Ben
--
I'm not just a number. To many, I'm known as a String...
Sep 8 '05 #13

"Ben Pope" <benpope81@_pan ts_gmail.com> wrote in message
news:1126171026 .d07cac1e0dd2a9 5b08c5ce3e65cb3 fcf@teranews...
Jon Slaughter wrote:
So my question is: Is there any way to use a class inside itself? Maybe a
pointer but I'd be wasting a pointer in those cases where I don't use the
class(as when the class itself is representing a properties class).
Best way I can put it into words if I'm trying to use one template to
represent two classes that are slightly different. Its sorta
polymorphism that isn't exact or maybe a "dynamic template" or something
like that. Maybe there is some more advanced ways that I'm not awear of
to do this sorta thing(after all, I'm kinda flying by the seat of my
pants at the moment and if I could just get pointed in the right
direction then I might be able to get a grip on it)?
You will need to forward declare the class and use pointers, you can't
have a class as a direct member of itself, because the size cannot be
determined (it's recursive).


Yes, but if I could someone create a template of the first one that is not
recursive and use that one in the recursive one then it wouldn't really be
recursive any more(well at most 1 lvl deep). Thats what I was trying to do
before but it didn't work out. I mean, basicaly the size can be determined
if its recusive but th the recursion has some finite end.. I think the
problem, atleast it seems, is that C++ doesn't have a way to know when to
stop the recursion. if I could do something like

class X
{
public:
X@3 Properties;
}

where the compiler would interpret @3 only accept 3 lvls deep and when it
gets to the 4 it removes that declaration then the recursion would end. I
suppose the problem with something like that is it just creates more
problems ;)

Have you thought about having something like the adaptor pattern against
a common implementation:

/* Common Implementation */
class MyClassImpl {
public:
void SomeFunc() {
// foo
}
};

/* Adaption 1 */
class MyClass1 {
MyClassImpl impl_;
public:
inline void SomeFunc_MyClas s1() {
impl_.SomeFunc( );
}
};

/* Adaption 2 */
class MyClass2 {
MyClassImpl impl_;
public:
inline void SomeFunc_MyClas s2() {
impl_.SomeFunc( );
}
};

So that you only have to maintain a very thin interface, not the
implementation?
I didn't think about that but it is a possibility. It does simplify the
process a great deal. I'll have to think more about how good an idea that
is. Not sure if it would be any better than just writing a utility to find
and replace the "key area" and duplicate it in a another file.

i.e.

class X
{
public:
X Properties;
}

then just create a simple util that finds "X Properties" and replaces it
with "Y Properties" then duplicates the exact same code in another file but
rename the class Y instead and remove the "X Properties".

So Y wouldn't be recursive but have the exact same methods and members(minus
properties) and then I'd just have to run this utility ever time I make a
major update to X(or have it run before the code is compiled automatically
by the IDE I guess).

You could also use inheritance, but in that case, probably MyClassImpl
will be abstract, and you'd probably want to inherit privately (or
protected).

How? You mean inherit MyClassImpl into the Adaptation classes? I could do
that but since I'm being so general with my method names I'd rather not use
inheritence... though you method can be used with the general names and
would have worked before when I didn't decide to make my template generic
too... its actually a pretty decent method but I think it might be more work
than just making a simple utility that duplicates the class and removes the
"recursion" aspect.

Basicaly I'm trying to completely get away from managing more than 1 class.
While your method does virtually eliminate the problem the utility method
completely eliminates it ;)
Ben
--
I'm not just a number. To many, I'm known as a String...

Thanks for the info though... I might actually use it after I think about
it. I'm not sure how much more my classes will grow and how much they will
end up being changed and even if there is C++ compatiable way to do it with
just one class/template.

Jon
Sep 8 '05 #14
Jon Slaughter wrote:
"Ben Pope" <benpope81@_pan ts_gmail.com> wrote in message
news:1126171026 .d07cac1e0dd2a9 5b08c5ce3e65cb3 fcf@teranews...
You will need to forward declare the class and use pointers, you can't
have a class as a direct member of itself, because the size cannot be
determined (it's recursive).

Yes, but if I could someone create a template of the first one that is not
recursive and use that one in the recursive one then it wouldn't really be
recursive any more(well at most 1 lvl deep). Thats what I was trying to do
before but it didn't work out. I mean, basicaly the size can be determined
if its recusive but th the recursion has some finite end.. I think the
problem, atleast it seems, is that C++ doesn't have a way to know when to
stop the recursion. if I could do something like

class X
{
public:
X@3 Properties;
}

where the compiler would interpret @3 only accept 3 lvls deep and when it
gets to the 4 it removes that declaration then the recursion would end. I
suppose the problem with something like that is it just creates more
problems ;)


Ahh yes, but the compiler is unlikely to be able to do that.

I'm not sure where it would get you, but you could probably do something
like:

template<int I>
class MyClass{
private:
MyClass<I-1>* child_;
}

And start off with:

MyClass<4> root;

But I'm not sure how you would terminate when I-1 = 0.
You could also use inheritance, but in that case, probably MyClassImpl
will be abstract, and you'd probably want to inherit privately (or
protected).

How? You mean inherit MyClassImpl into the Adaptation classes? I could do
that but since I'm being so general with my method names I'd rather not use
inheritence...


Yes:

/* Common Abstract Implementation */
class MyClassImpl {
public:
void SomeFunc() {
// foo
}
virtual ~MyClassImpl() = 0;
};

/* Adaption 1 */
class MyClass1 : MyClassImpl {
public:
inline void SomeFunc_MyClas s1() {
MyClassImpl::So meFunc();
}
};

With private or protected inheritance you're inheriting the
implementation the method names are irrelevant, in fact, thats the sole
purpose of using the wrapper... to just change the method names.
though you method can be used with the general names and
would have worked before when I didn't decide to make my template generic
too... its actually a pretty decent method but I think it might be more work
than just making a simple utility that duplicates the class and removes the
"recursion" aspect.
I'm not so sure... I suspect the utility will take a lot longer than you
expect it will, by the time it's debugged and working.
Basicaly I'm trying to completely get away from managing more than 1 class.
While your method does virtually eliminate the problem the utility method
completely eliminates it ;)
Well, personally I think it just shifts the problem from writing the
code to writing the utility.
Thanks for the info though... I might actually use it after I think about
it. I'm not sure how much more my classes will grow and how much they will
end up being changed and even if there is C++ compatiable way to do it with
just one class/template.


If you want to have the different names you'll have to maintain them
yourself, it's the simplest C++ way I can think of. By the time you
write a utility and test it and faff around when it doesn't work, and
then decide that actually there is a difference between your classes and
try to work that into your utility... You might as well have just
written the wrappers. They are so simple that there should be no
overhead in space or time for the code.

Ben
--
I'm not just a number. To many, I'm known as a String...
Sep 8 '05 #15
Ben Pope wrote:
Jon Slaughter wrote:
"Ben Pope" <benpope81@_pan ts_gmail.com> wrote in message
news:1126171026 .d07cac1e0dd2a9 5b08c5ce3e65cb3 fcf@teranews...
You will need to forward declare the class and use pointers, you
can't
have a class as a direct member of itself, because the size cannot
be determined (it's recursive).

Yes, but if I could someone create a template of the first one that
is not recursive and use that one in the recursive one then it
wouldn't really be recursive any more(well at most 1 lvl deep).
Thats what I was trying to do before but it didn't work out. I mean,
basicaly the size can be determined if its recusive but th the
recursion has some finite end.. I think the problem, atleast it
seems, is that C++ doesn't have a way to know when to stop the
recursion. if I could do something like

class X
{
public:
X@3 Properties;
}

where the compiler would interpret @3 only accept 3 lvls deep and
when it gets to the 4 it removes that declaration then the recursion
would end. I suppose the problem with something like that is it
just creates more problems ;)


Ahh yes, but the compiler is unlikely to be able to do that.

I'm not sure where it would get you, but you could probably do
something like:

template<int I>
class MyClass{
private:
MyClass<I-1>* child_;
}

And start off with:

MyClass<4> root;

But I'm not sure how you would terminate when I-1 = 0.


You would specialise the template for the case 'I equals 0'; this will
terminate the recursion.
template<>
class MyClass<0>{
};

The MyClass<4> type would then look like this:

MyClass<4> {
MyClass<3>* child_;
};

MyClass<3> {
MyClass<2>* child_;
};

MyClass<2> {
MyClass<1>* child_;
};

MyClass<1> {
MyClass<0>* child_; // No more kids after this one
};
You could also use inheritance, but in that case, probably
MyClassImpl
will be abstract, and you'd probably want to inherit privately (or
protected).

How? You mean inherit MyClassImpl into the Adaptation classes? I
could do that but since I'm being so general with my method names
I'd rather not use inheritence...


Yes:

/* Common Abstract Implementation */
class MyClassImpl {
public:
void SomeFunc() {
// foo
}
virtual ~MyClassImpl() = 0;
};

/* Adaption 1 */
class MyClass1 : MyClassImpl {
public:
inline void SomeFunc_MyClas s1() {
MyClassImpl::So meFunc();
}
};

With private or protected inheritance you're inheriting the
implementation the method names are irrelevant, in fact, thats the
sole purpose of using the wrapper... to just change the method names.
> though you method can be used with the general names and
would have worked before when I didn't decide to make my template
generic too... its actually a pretty decent method but I think it
might be more work than just making a simple utility that duplicates
the class and removes the "recursion" aspect.


I'm not so sure... I suspect the utility will take a lot longer than
you expect it will, by the time it's debugged and working.
Basicaly I'm trying to completely get away from managing more than 1
class. While your method does virtually eliminate the problem the
utility method completely eliminates it ;)


Well, personally I think it just shifts the problem from writing the
code to writing the utility.
Thanks for the info though... I might actually use it after I think
about it. I'm not sure how much more my classes will grow and how
much they will end up being changed and even if there is C++
compatiable way to do it with just one class/template.


If you want to have the different names you'll have to maintain them
yourself, it's the simplest C++ way I can think of. By the time you
write a utility and test it and faff around when it doesn't work, and
then decide that actually there is a difference between your classes
and
try to work that into your utility... You might as well have just
written the wrappers. They are so simple that there should be no
overhead in space or time for the code.

Ben

Sep 10 '05 #16

"Ben Pope" <benpope81@_pan ts_gmail.com> wrote in message
news:1126182709 .89ac7e9493069b 87dcef75fdf0723 810@teranews...
Jon Slaughter wrote:
"Ben Pope" <benpope81@_pan ts_gmail.com> wrote in message
news:1126171026 .d07cac1e0dd2a9 5b08c5ce3e65cb3 fcf@teranews...
<snip>

well I basicaly just made a generic class as several have said to do and
made a utility to duplicate the class and add some deep copy code to the
copy constructor. The utility only took about 30 mins to do and setup in my
build project. Its just a hack but it will allow me to only have to worry
about 1 class(ofcourse it only looks for tokens and modifies them and so if
the syntax is wrong or it can screw everything up. But in this case not much
has to be changed that requires any syntatic analysis).
Going to look at that recursive procedure you mentioned with Tim's advice
too. Seems like C++ can handle what I need ;) I'll check it out and report
on how it turns out.

Ben
--
I'm not just a number. To many, I'm known as a String...


Thanks
Jon
Sep 11 '05 #17

"Tim Clacy" <no*******@nosp amphaseone.nosp amdk> wrote in message
news:43******** *************** @dread12.news.t ele.dk...
Ben Pope wrote:
Jon Slaughter wrote:
"Ben Pope" <benpope81@_pan ts_gmail.com> wrote in message
news:1126171026 .d07cac1e0dd2a9 5b08c5ce3e65cb3 fcf@teranews...

You will need to forward declare the class and use pointers, you
can't
have a class as a direct member of itself, because the size cannot
be determined (it's recursive).
Yes, but if I could someone create a template of the first one that
is not recursive and use that one in the recursive one then it
wouldn't really be recursive any more(well at most 1 lvl deep).
Thats what I was trying to do before but it didn't work out. I mean,
basicaly the size can be determined if its recusive but th the
recursion has some finite end.. I think the problem, atleast it
seems, is that C++ doesn't have a way to know when to stop the
recursion. if I could do something like

class X
{
public:
X@3 Properties;
}

where the compiler would interpret @3 only accept 3 lvls deep and
when it gets to the 4 it removes that declaration then the recursion
would end. I suppose the problem with something like that is it
just creates more problems ;)


Ahh yes, but the compiler is unlikely to be able to do that.

I'm not sure where it would get you, but you could probably do
something like:

template<int I>
class MyClass{
private:
MyClass<I-1>* child_;
}

And start off with:

MyClass<4> root;

But I'm not sure how you would terminate when I-1 = 0.


You would specialise the template for the case 'I equals 0'; this will
terminate the recursion.
template<>
class MyClass<0>{
};

The MyClass<4> type would then look like this:

MyClass<4> {
MyClass<3>* child_;
};

MyClass<3> {
MyClass<2>* child_;
};

MyClass<2> {
MyClass<1>* child_;
};

MyClass<1> {
MyClass<0>* child_; // No more kids after this one
};


AWESOME!!! Almost exactly what I need! it does the job almost perfectly but
one complaint is that the terminal class is still represented... but since
its empty its not that big a deal.

Is there anywhere I can learn more about "advanced" template programming?
This recursive ability seems like a very powerful feature and I never
expected C++ to be able to do it. Surely there are more powerful features
like this?

I'm virtually completely new to the concept of templates and so I just have
a basic grasp of what they do but I can't seem to find any good information
online about them. Documentation isn't what it used to be and it seems like
I just end up going around in circles trying to find something specific but
never get it.

Is there any book worth that goes into a good deal of depth on the
"advanced" features of C++. (I'm not saying that the above is advanced but
that it not something that I would have ordinarily thought possible because,
mainly, I didn't know you could have a "template counter" and specialize
it).

Thanks for the help!! I really appreciate it!

Still might run into some problems but I think I can probably hack it out.

Jon
Sep 11 '05 #18
> Is there anywhere I can learn more about "advanced" template programming?
This recursive ability seems like a very powerful feature and I never
expected C++ to be able to do it. Surely there are more powerful features
like this?


Modern C++ Design, by Andrei Alexandrescu is an awesome book on
programming with templates.

john
Sep 11 '05 #19

"John Harrison" <jo************ *@hotmail.com> wrote in message
news:49******** *********@newsf e4-gui.ntli.net...
Is there anywhere I can learn more about "advanced" template programming?
This recursive ability seems like a very powerful feature and I never
expected C++ to be able to do it. Surely there are more powerful
features like this?


Modern C++ Design, by Andrei Alexandrescu is an awesome book on
programming with templates.

john


Thanks, I'll check it out.

Jon
Sep 11 '05 #20

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
10795
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10512
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
10550
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
10220
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
9332
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
6957
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5627
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5796
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
3
3083
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.