473,408 Members | 2,832 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,408 software developers and data experts.

Macro var args

Hello all,

right now, i'm using the following macro to automatically add informations
to exceptions:

#define THROW(Class, args...) throw Class(__FILE__, __LINE__, ## args)

but AFAIK, it's gcc specific. Is there a way to do it in a standard c++ way?

TIA

--
TheDD
Jul 22 '05 #1
27 5883
TheDD <pa*********@pas.de.spam.fr> wrote in
news:c8**********@news-reader2.wanadoo.fr:
Hello all,

right now, i'm using the following macro to automatically add
informations to exceptions:

#define THROW(Class, args...) throw Class(__FILE__, __LINE__, ## args)

but AFAIK, it's gcc specific. Is there a way to do it in a standard
c++ way?


Not really.

Though, there's a very interesting alternative technique.

See the following article by Andrei Alexandrescu and John Torjo.
http://www.cuj.com/documents/s=8464/...8alexandr.html

--
:: bartekd [at] o2 [dot] pl

Jul 22 '05 #2
TheDD wrote:
Hello all,

right now, i'm using the following macro to automatically add informations
to exceptions:

#define THROW(Class, args...) throw Class(__FILE__, __LINE__, ## args)

but AFAIK, it's gcc specific. Is there a way to do it in a standard c++ way?

TIA

How about syntax like:

Throw<Class>( ... )

Here is an example:

#define Throw throw Thrower(__FILE__, __LINE__).DoThrow

struct Thrower
{
const char * file;
int line;

Thrower( const char * file, int line )
: file( file ), line( line )
{
}

template <typename T>
inline T DoThrow()
{
return T( file, line );
}

template <
typename T,
typename T0 inline T DoThrow( T0 & a0 )
{
return T( file, line, a0 );
}

template <
typename T,
typename T0,
typename T1 inline T DoThrow( T0 & a0, T1 & a1 )
{
return T( file, line, a0, a1 );
}

template <
typename T,
typename T0,
typename T1,
typename T2

inline T DoThrow( T0 & a0, T1 & a1, T2 & a2 )
{
return T( file, line, a0, a1, a2 );
}

// define the DoThrow template for as many args as you need

};

struct Ex1
{
Ex1( const char * s );
};

struct Ex2
{
Ex2( const char * s, const char * s1 );
};

void foo()
{

Throw<Ex2>( "A", "B ");

Throw<Ex1>( "A" );

}

Jul 22 '05 #3
"TheDD" <pa*********@pas.de.spam.fr> wrote...
right now, i'm using the following macro to automatically add informations
to exceptions:

#define THROW(Class, args...) throw Class(__FILE__, __LINE__, ## args)

but AFAIK, it's gcc specific. Is there a way to do it in a standard c++

way?

No. The usual approach is to have as many macros as you might ever need,
each with one more argument than the last one.

#define THROW0(Class) throw Class(__FILE__,__LINE__)
#define THROW1(Class,a) throw Class(__FILE__,__LINE__,a)

and so on...

Victor
Jul 22 '05 #4
Victor Bazarov wrote:
"TheDD" <pa*********@pas.de.spam.fr> wrote...
right now, i'm using the following macro to automatically add
informations to exceptions:

#define THROW(Class, args...) throw Class(__FILE__, __LINE__, ## args)

but AFAIK, it's gcc specific. Is there a way to do it in a standard c++

way?

No. The usual approach is to have as many macros as you might ever need,
each with one more argument than the last one.

#define THROW0(Class) throw Class(__FILE__,__LINE__)
#define THROW1(Class,a) throw Class(__FILE__,__LINE__,a)

and so on...

Victor


Thx, it's a lot simpler than the solution proposed by Gianni.

Well my code won't be compiler-portable unless really needed.

--
TheDD
Jul 22 '05 #5
"TheDD" <pa*********@pas.de.spam.fr> wrote in message
news:c85980$uor$1@news-
#define THROW(Class, args...) throw Class(__FILE__, __LINE__, ## args)

but AFAIK, it's gcc specific. Is there a way to do it in a standard c++

way?

I must be missing something, but why is it gcc specific? Maybe it's the ...
and ## notation?

In gcc you can also use __FUNCTION__ but that's not standard
(unfortunately).

Anyway, can you get by with just one argument? Once I wrote a class
args<T,N> for this. You can also use a std::vector<T>, or va_list if you
know the number of the objects and types as long as these are fundamental
types. You could also call set functions on the exception object prior to
throwing it and a chaining operator << sounds like a good idea.

(But you still need a macro to create the exception object because an inline
function would encode the __LINE__ of the inline function which would hardly
be useful at all).
Jul 22 '05 #6
Siemel Naran wrote:
#define THROW(Class, args...) throw Class(__FILE__, __LINE__, ## args)

but AFAIK, it's gcc specific. Is there a way to do it in a standard c++ way?

I must be missing something, but why is it gcc specific? Maybe it's the
... and ## notation?


http://docs.freebsd.org/info/gcc/gcc...o_Varargs.html

I used to believe that "..." was ok in a macro but it doesn't seem to be the
case. And the "...args" and ", ## args" notations are even worse i think.
In gcc you can also use __FUNCTION__ but that's not standard
(unfortunately).

Anyway, can you get by with just one argument? Once I wrote a class
args<T,N> for this. You can also use a std::vector<T>, or va_list if you
know the number of the objects and types as long as these are fundamental
i don't
types. You could also call set functions on the exception object prior to
throwing it and a chaining operator << sounds like a good idea.

(But you still need a macro to create the exception object because an
inline function would encode the __LINE__ of the inline function which
would hardly be useful at all).


well i will keep the macro until i really need to change it (after some
time, i will be able to see how many arguments i need).

--
TheDD
Jul 22 '05 #7
"TheDD" <pa*********@pas.de.spam.fr> wrote in message
news:c861i0$tdq$1@news-
Siemel Naran wrote:
Anyway, can you get by with just one argument? Once I wrote a class
args<T,N> for this. You can also use a std::vector<T>, or va_list if you know the number of the objects and types as long as these are fundamental
i don't
With va_list one often uses the convention that the last entry is NULL.
Thus f("hello", "world", NULL) and so the va_list knows where to end.
types. You could also call set functions on the exception object prior to throwing it and a chaining operator << sounds like a good idea.

well i will keep the macro until i really need to change it (after some
time, i will be able to see how many arguments i need).


But won't chaining work?

throw Class(__FILE_, __FUNCTION__, __LINE__) << "abc" << "def";

You can even replace "abc" with a NameValue pair if that's what you want.

throw Class(__FILE_, __FUNCTION__, __LINE__) << Pair("abc", "def");
As for class args<T, N> it goes something like this:
template <size_t N>
void test_args1(ostream& out, const enhanced::args<int,N>& arg);

void test_args(ostream& out)
{
enhanced::args<int,0> empty;
test_args1(out,empty+2+3+4);
}

/////

template <typename T, int N>
class args
{
public:
args(const args<T,N-1>& first, T rest) : d_first(first), d_rest(rest)
{ }

args<T,N+1> operator+(T rest) const
{
return args<T,N+1>(*this,rest);
}

template <class U> void for_each(U u) const
{
d_first.for_each(u);
u(d_rest);
}

template <class Iter> Iter copy(Iter dest) const
{
dest=d_first.copy(dest);
*dest=d_rest;
return ++dest;
}

private:
args<T,N-1> d_first;
T d_rest;
};
template <typename T>
class args<T,1>
{
public:
explicit args(T rest) : d_rest(rest) { }

args<T,2> operator+(T rest) const
{
return args<T,2>(*this,rest);
}

template <class U> void for_each(U u) const
{
u(d_rest);
}

template <class Iter> Iter copy(Iter dest) const
{
*dest=d_rest;
return ++dest;
}
private:
T d_rest;
};
template <typename T>
class args<T,0>
{
public:
args() { }

args<T,1> operator+(T rest) const
{
return args<T,1>(rest);
}
};


Jul 22 '05 #8
On Sat, 15 May 2004 22:08:46 GMT, Siemel Naran wrote:
"TheDD" <pa*********@pas.de.spam.fr> wrote in message
news:c861i0$tdq$1@news-
Siemel Naran wrote:
Anyway, can you get by with just one argument? Once I wrote a class
args<T,N> for this. You can also use a std::vector<T>, or va_list if you know the number of the objects and types as long as these are fundamental

i don't


With va_list one often uses the convention that the last entry is NULL.
Thus f("hello", "world", NULL) and so the va_list knows where to end.


if (bad)
throw Class(__FILE__, __FUNCTION__, __LINE__) << f("hello");

?
types. You could also call set functions on the exception object prior to throwing it and a chaining operator << sounds like a good idea.

well i will keep the macro until i really need to change it (after some
time, i will be able to see how many arguments i need).


But won't chaining work?

throw Class(__FILE_, __FUNCTION__, __LINE__) << "abc" << "def";

You can even replace "abc" with a NameValue pair if that's what you want.

throw Class(__FILE_, __FUNCTION__, __LINE__) << Pair("abc", "def");

As for class args<T, N> it goes something like this:

template <size_t N>
void test_args1(ostream& out, const enhanced::args<int,N>& arg);

void test_args(ostream& out)
{
enhanced::args<int,0> empty;
test_args1(out,empty+2+3+4);
}

/////

template <typename T, int N>
class args
{
public:
args(const args<T,N-1>& first, T rest) : d_first(first), d_rest(rest)
{ }

args<T,N+1> operator+(T rest) const
{
return args<T,N+1>(*this,rest);
}

template <class U> void for_each(U u) const
{
d_first.for_each(u);
u(d_rest);
}

template <class Iter> Iter copy(Iter dest) const
{
dest=d_first.copy(dest);
*dest=d_rest;
return ++dest;
}

private:
args<T,N-1> d_first;
T d_rest;
};

template <typename T>
class args<T,1>
{
public:
explicit args(T rest) : d_rest(rest) { }

args<T,2> operator+(T rest) const
{
return args<T,2>(*this,rest);
}

template <class U> void for_each(U u) const
{
u(d_rest);
}

template <class Iter> Iter copy(Iter dest) const
{
*dest=d_rest;
return ++dest;
}

private:
T d_rest;
};

template <typename T>
class args<T,0>
{
public:
args() { }

args<T,1> operator+(T rest) const
{
return args<T,1>(rest);
}
};


I'm sorry, i don't quite fully understand the code.

Let's say i want to throw something:

if (bad)
throw Class(__FILE_, __FUNCTION__, __LINE__) << args<int, 0> +
args<string, "foo">;

?

1/ I remember that string are difficult to use as template parameters.
2/ The code looks awful, is complicated for not much, facilitate
errors, and is probably slow (i don't manage to get when the arguments
evaluation occurs).

The aim for the macro was to make it simple, clean and easily
readable. Thx a lot for your help and your time, i knwo "it's for
free", but your solution doesn't fit my needs.

--
TheDD
Jul 22 '05 #9
TheDD wrote:
Hello all,

right now, i'm using the following macro to automatically add informations
to exceptions:

#define THROW(Class, args...) throw Class(__FILE__, __LINE__, ## args)

but AFAIK, it's gcc specific. Is there a way to do it in a standard c++ way?

TIA

If you're interested in the line of your code you can use the function
assert(). But it's not the same thing.

Anil Mamede

Jul 22 '05 #10
* TheDD <pa*********@pas.de.spam.fr> schriebt:
Hello all,

right now, i'm using the following macro to automatically add informations
to exceptions:

#define THROW(Class, args...) throw Class(__FILE__, __LINE__, ## args)

but AFAIK, it's gcc specific. Is there a way to do it in a standard c++ way?


If the problem is simply to pass a variable number of arguments then that is
trivial in standard C++, but since nobody else have mentioned it I may
be wrong about what the problem is.

Anyway, here's one way -- there are many others:
class RhubarbStew: public std::runtime_error
{
public:
RhubarbStew( Foo const&, Bar const& );
...
virtual void doThrow( std::string const&, unsigned long ) const;
};

#define THROW( Class, Args ) Class( Args ).doThrow( __FILE__, __LINE__ )

int main()
{
try
{
THROW( RhubarbStew, (Foo( 1, 2, 3), Bar( "huh?" )) );
return EXIT_SUCCESS;
}
catch( std::exception const& )
{
return EXIT_FAILURE;
}
}
Of course the only saving is to avoid typing __FILE__ and __LINE__, and that
I think is much better expressed by e.g.
class SourceCodeRef
{
private:
std::string myFileName;
unsigned long myLineNumber;
public:
SourceCodeRef( std::string const& file, unsigned long line )
: myFileName( file ), myLineNumber( line )
{}

std::string fileName() const { return myFileName }
unsigned long lineNumber() const { return myLineNumber }
};

#define SOURCECODEREF SourceCodeRef( __FILE__, __LINE__ )

...

RhubarbStew( SOURCECODEREF, Foo( 1, 2, 3 ), Bar( "Huh?" ) ).doThrow();
In short, I think that perhaps you're trying to put too much into your
macro, which not only makes it complicated but hinders reuse.

--
A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 22 '05 #11
Alf P. Steinbach wrote:
* TheDD <pa*********@pas.de.spam.fr> schriebt:
Hello all,

right now, i'm using the following macro to automatically add
informations to exceptions:

#define THROW(Class, args...) throw Class(__FILE__, __LINE__, ## args)

but AFAIK, it's gcc specific. Is there a way to do it in a standard c++
way?


If the problem is simply to pass a variable number of arguments then that
is trivial in standard C++, but since nobody else have mentioned it I may
be wrong about what the problem is.

Anyway, here's one way -- there are many others:
class RhubarbStew: public std::runtime_error
{
public:
RhubarbStew( Foo const&, Bar const& );
...
virtual void doThrow( std::string const&, unsigned long ) const;
};

#define THROW( Class, Args ) Class( Args ).doThrow( __FILE__, __LINE__
#)

int main()
{
try
{
THROW( RhubarbStew, (Foo( 1, 2, 3), Bar( "huh?" )) );
return EXIT_SUCCESS;
}
catch( std::exception const& )
{
return EXIT_FAILURE;
}
}
Of course the only saving is to avoid typing __FILE__ and __LINE__, and
that I think is much better expressed by e.g.
class SourceCodeRef
{
private:
std::string myFileName;
unsigned long myLineNumber;
public:
SourceCodeRef( std::string const& file, unsigned long line )
: myFileName( file ), myLineNumber( line )
{}

std::string fileName() const { return myFileName }
unsigned long lineNumber() const { return myLineNumber }
};

#define SOURCECODEREF SourceCodeRef( __FILE__, __LINE__ )

...

RhubarbStew( SOURCECODEREF, Foo( 1, 2, 3 ), Bar( "Huh?" ) ).doThrow();
In short, I think that perhaps you're trying to put too much into your
macro, which not only makes it complicated but hinders reuse.


Well a one line macro complicated? i disagree.

I've tried to compile your code:

$ cat -n throw.cc
1 #include <string>
2
3 class Ex
4 {
5 public:
6 Ex(const char *msg, int no)
7 : msg(msg), no(no)
8 {
9 };
10 virtual void doThrow(const char * file, int line)
11 {
12 this->file = file;
13 this->line = line;
14 };
15
16 protected:
17 std::string msg;
18 std::string file;
19 int line;
20 int no;
21 };
22
23 #define THROW(Class, Args) Class(Args).doThrow(__FILE__, __LINE__)
24
25 int main()
26 {
27 try
28 {
29 THROW(Ex, ("blah", 1));
30 return EXIT_SUCCESS;
31 }
32 catch (...)
33 {
34 return EXIT_FAILURE;
35 }
36 }

$ g++ -Wall throw.cc
throw.cc:4: warning: `class Ex' has virtual functions but non-virtual
destructor
throw.cc: In function `int main()':
throw.cc:29: warning: left-hand operand of comma expression has no effect
throw.cc:29: error: no matching function for call to `Ex::Ex(int)'
throw.cc:4: error: candidates are: Ex::Ex(const Ex&)
throw.cc:7: error: Ex::Ex(const char*, int)

It seems to me that (expr1, expr2, expr3) "return" expr3 only. So it doesn't
seems to work, but it's probable i've missed something.

--
TheDD
Jul 22 '05 #12
* TheDD <pa*********@pas.de.spam.fr> schriebt:
Alf P. Steinbach wrote:
* TheDD <pa*********@pas.de.spam.fr> schriebt:
Hello all,

right now, i'm using the following macro to automatically add
informations to exceptions:

#define THROW(Class, args...) throw Class(__FILE__, __LINE__, ## args)

but AFAIK, it's gcc specific. Is there a way to do it in a standard c++
way?
If the problem is simply to pass a variable number of arguments then that
is trivial in standard C++, but since nobody else have mentioned it I may
be wrong about what the problem is.

Anyway, here's one way -- there are many others:
class RhubarbStew: public std::runtime_error
{
public:
RhubarbStew( Foo const&, Bar const& );
...
virtual void doThrow( std::string const&, unsigned long ) const;
};

#define THROW( Class, Args ) Class( Args ).doThrow( __FILE__, __LINE__
#)

int main()
{
try
{
THROW( RhubarbStew, (Foo( 1, 2, 3), Bar( "huh?" )) );
return EXIT_SUCCESS;
}
catch( std::exception const& )
{
return EXIT_FAILURE;
}
}
Of course the only saving is to avoid typing __FILE__ and __LINE__, and
that I think is much better expressed by e.g.
class SourceCodeRef
{
private:
std::string myFileName;
unsigned long myLineNumber;
public:
SourceCodeRef( std::string const& file, unsigned long line )
: myFileName( file ), myLineNumber( line )
{}

std::string fileName() const { return myFileName }
unsigned long lineNumber() const { return myLineNumber }
};

#define SOURCECODEREF SourceCodeRef( __FILE__, __LINE__ )

...

RhubarbStew( SOURCECODEREF, Foo( 1, 2, 3 ), Bar( "Huh?" ) ).doThrow();
In short, I think that perhaps you're trying to put too much into your
macro, which not only makes it complicated but hinders reuse.


Well a one line macro complicated? i disagree.


It adds complication in many ways, just trust me on that.

I've tried to compile your code:

It seems to me that (expr1, expr2, expr3) "return" expr3 only. So it doesn't
seems to work, but it's probable i've missed something.


I typed it in off-the-cuff and unfortunately added an extranous
parenthesis in the macro definition. A typo. Do you see it?

--
A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 22 '05 #13
Alf P. Steinbach wrote:
* TheDD <pa*********@pas.de.spam.fr> schriebt:
Alf P. Steinbach wrote:
> * TheDD <pa*********@pas.de.spam.fr> schriebt:
>> Hello all,
>>
>> right now, i'm using the following macro to automatically add
>> informations to exceptions:
>>
>> #define THROW(Class, args...) throw Class(__FILE__, __LINE__, ## args)
>>
>> but AFAIK, it's gcc specific. Is there a way to do it in a standard
>> c++ way?
>
> If the problem is simply to pass a variable number of arguments then
> that is trivial in standard C++, but since nobody else have mentioned
> it I may be wrong about what the problem is.
>
> Anyway, here's one way -- there are many others:
>
>
> class RhubarbStew: public std::runtime_error
> {
> public:
> RhubarbStew( Foo const&, Bar const& );
> ...
> virtual void doThrow( std::string const&, unsigned long )
> const;
> };
>
> #define THROW( Class, Args ) Class( Args ).doThrow( __FILE__,
> #__LINE__ )
>
> int main()
> {
> try
> {
> THROW( RhubarbStew, (Foo( 1, 2, 3), Bar( "huh?" )) );
> return EXIT_SUCCESS;
> }
> catch( std::exception const& )
> {
> return EXIT_FAILURE;
> }
> }
>
>
> Of course the only saving is to avoid typing __FILE__ and __LINE__, and
> that I think is much better expressed by e.g.
>
>
> class SourceCodeRef
> {
> private:
> std::string myFileName;
> unsigned long myLineNumber;
> public:
> SourceCodeRef( std::string const& file, unsigned long line )
> : myFileName( file ), myLineNumber( line )
> {}
>
> std::string fileName() const { return myFileName }
> unsigned long lineNumber() const { return myLineNumber }
> };
>
> #define SOURCECODEREF SourceCodeRef( __FILE__, __LINE__ )
>
> ...
>
> RhubarbStew( SOURCECODEREF, Foo( 1, 2, 3 ), Bar( "Huh?" )
> ).doThrow();
>
>
> In short, I think that perhaps you're trying to put too much into your
> macro, which not only makes it complicated but hinders reuse.


Well a one line macro complicated? i disagree.


It adds complication in many ways, just trust me on that.

I've tried to compile your code:

It seems to me that (expr1, expr2, expr3) "return" expr3 only. So it
doesn't seems to work, but it's probable i've missed something.


I typed it in off-the-cuff and unfortunately added an extranous
parenthesis in the macro definition. A typo. Do you see it?


Yes:

#define THROW(Class, Args) Class Args .doThrow(__FILE__, __LINE__)

Thx a lot :)

For some reason, i have compiler errors in my real project, while the "proof
of concept" code compiles. Need some investigations ;)
--
TheDD
Jul 22 '05 #14
TheDD wrote:
Alf P. Steinbach wrote:
* TheDD <pa*********@pas.de.spam.fr> schriebt:
Alf P. Steinbach wrote:

> * TheDD <pa*********@pas.de.spam.fr> schriebt:
>> Hello all,
>>
>> right now, i'm using the following macro to automatically add
>> informations to exceptions:
>>
>> #define THROW(Class, args...) throw Class(__FILE__, __LINE__, ##
>> #args)
>>
>> but AFAIK, it's gcc specific. Is there a way to do it in a standard
>> c++ way?
>
> If the problem is simply to pass a variable number of arguments then
> that is trivial in standard C++, but since nobody else have mentioned
> it I may be wrong about what the problem is.
>
> Anyway, here's one way -- there are many others:
>
>
> class RhubarbStew: public std::runtime_error
> {
> public:
> RhubarbStew( Foo const&, Bar const& );
> ...
> virtual void doThrow( std::string const&, unsigned long )
> const;
> };
>
> #define THROW( Class, Args ) Class( Args ).doThrow( __FILE__,
> #__LINE__ )
>
> int main()
> {
> try
> {
> THROW( RhubarbStew, (Foo( 1, 2, 3), Bar( "huh?" )) );
> return EXIT_SUCCESS;
> }
> catch( std::exception const& )
> {
> return EXIT_FAILURE;
> }
> }
>
>
> Of course the only saving is to avoid typing __FILE__ and __LINE__,
> and that I think is much better expressed by e.g.
>
>
> class SourceCodeRef
> {
> private:
> std::string myFileName;
> unsigned long myLineNumber;
> public:
> SourceCodeRef( std::string const& file, unsigned long line )
> : myFileName( file ), myLineNumber( line )
> {}
>
> std::string fileName() const { return myFileName }
> unsigned long lineNumber() const { return myLineNumber }
> };
>
> #define SOURCECODEREF SourceCodeRef( __FILE__, __LINE__ )
>
> ...
>
> RhubarbStew( SOURCECODEREF, Foo( 1, 2, 3 ), Bar( "Huh?" )
> ).doThrow();
>
>
> In short, I think that perhaps you're trying to put too much into your
> macro, which not only makes it complicated but hinders reuse.

Well a one line macro complicated? i disagree.


It adds complication in many ways, just trust me on that.

I've tried to compile your code:

It seems to me that (expr1, expr2, expr3) "return" expr3 only. So it
doesn't seems to work, but it's probable i've missed something.


I typed it in off-the-cuff and unfortunately added an extranous
parenthesis in the macro definition. A typo. Do you see it?


Yes:

#define THROW(Class, Args) Class Args .doThrow(__FILE__, __LINE__)

Thx a lot :)

For some reason, i have compiler errors in my real project, while the
"proof of concept" code compiles. Need some investigations ;)


I was missing something:

$ cat -n throw.cc
1 #include <string>
2
3 class Ex
4 {
5 public:
6 Ex(const char *msg, int no)
7 : msg(msg), no(no)
8 {
9 };
10
11 void doThrow(const char * file, int line)
12 {
13 this->file = file;
14 this->line = line;
15
16 throw *this; // was missing
17 };
18
19 protected:
20 std::string msg;
21 std::string file;
22 int line;
23 int no;
24 };
25 // throw removed
26 #define THROW(Class, Args) Class Args .doThrow(__FILE__, __LINE__)
27
28 int main()
29 {
30 try
31 {
32 THROW(Ex, ("blah", 1));
33 return EXIT_SUCCESS;
34 }
35 catch( std::exception const& )
36 {
37 return EXIT_FAILURE;
38 }
39 }

Now my project compiles.

But with this macro, the exception is allocated on the stack. And i don't
know for the throw case. Must i create a copy in the heap or is "throw
*this" ok?

--
TheDD
Jul 22 '05 #15
TheDD wrote:
[...]
Now my project compiles.
but doesn't work, after some tests:

throw-a.c : doThrow non virtual and only in base class
throw-b.c : doThrow virtual and only in base class
throw-c.c : doThrow(s) non virtual and in all class
throw-d.c : doThrow(s) virtual and in all class

$ cat -n throw-a.cc
1 #include <string>
2 #include <iostream>
3
4 class Ex
5 {
6 public:
7 Ex()
8 {
9 };
10
11 void doThrow(const char * file, int line)
12 {
13 this->file = file;
14 this->line = line;
15
16 std::cerr << "Ex::doThrow, name = " << typeid(*this).name()
17 << std::endl;
18 throw *this;
19 };
20
21 protected:
22 std::string file;
23 int line;
24 };
25
26 class Ex2 : public Ex
27 {
28 public:
29 Ex2(const char *msg)
30 : msg(msg)
31 {
32 };
33 protected:
34 std::string msg;
35 };
36
37 #define THROW(Class, Args) Class Args .doThrow(__FILE__, __LINE__)
38
39 int main()
40 {
41 try
42 {
43 THROW(Ex2, ("blah"));
44 return EXIT_SUCCESS;
45 }
46 catch (Ex & ex)
47 {
48 std::cerr << "name = " << typeid(ex).name() << std::endl;
49 return EXIT_FAILURE;
50 }
51 }

$ g++ throw-a.cc && ./a.out
Ex::doThrow, name = 2Ex
name = 2Ex

The type of this is the static type because doThrow is not virtual, so:


$ diff throw-a.cc throw-b.cc
11c11
< void doThrow(const char * file, int line)
--- virtual void doThrow(const char * file, int line) $ g++ throw-b.cc && ./a.out
Ex::doThrow, name = 3Ex2
name = 2Ex

The dynamic type is lost so i have to copy the doThrow method for each
class:


$ diff throw-b.cc throw-d.cc
32a33,43
virtual void doThrow(const char * file, int line)
{
this->file = file;
this->line = line;

std::cerr << "Ex2::doThrow, name = " << typeid(*this).name()
<< std::endl;
throw *this;
};
$ g++ throw-d.cc && ./a.out
Ex2::doThrow, name = 3Ex2
name = 3Ex2

Now it works.


For some reason, having the method non virtual in each class do not work:

$ diff throw-a.cc throw-c.cc
32a33,43
void doThrow(const char * file, int line)
{
this->file = file;
this->line = line;

std::cerr << "Ex2::doThrow, name = " << typeid(*this).name()
<< std::endl;
throw *this;
};


$ g++ throw-c.cc && ./a.out
Ex2::doThrow, name = 3Ex2
name = 2Ex
The method is really not handy, since i have to copy the same code for each
class or i could use template thing maybe but it doesn't worth it.

I think i'm getting back the old method :(

--
TheDD
Jul 22 '05 #16
* TheDD <pa*********@pas.de.spam.fr> schriebt:

I was missing something:

$ cat -n throw.cc
1 #include <string>
2
3 class Ex
This should derive from std::runtime_error, or your catch in 'main' will
not.

With derivation from std::runtime_error you don't need the msg member.
4 {
5 public:
6 Ex(const char *msg, int no)
7 : msg(msg), no(no)
8 {
9 };
10
11 void doThrow(const char * file, int line)
Should be const (and that implies not modifying members).

Also, part of what makes a doThrow function useful is that it can be used
to throw an object you have a polymorphic reference to.

In order to support that it should also be virtual.

12 {
13 this->file = file;
14 this->line = line;
15
16 throw *this; // was missing
17 };
18
19 protected:
20 std::string msg;
21 std::string file;
22 int line;
23 int no;
24 };
I suggest something like (off the cuff)

class SourceCodeRef
{
private:
std::string myFileName;
int myLineNumber;
public:
SourceCodeRef( char const fileName[], int lineNumber )
: myFileName( fileName ), myLineNumber( lineNumber )
{}

std::string fileName() const { return myFileName; }
int lineNumber() const { return myLineNumber; }
};

#define SOURCECODEREF SourceCodeRef( __FILE__, __LINE__ )
class Ex: public std::runtime_error
{
private:
int myErrorCode;
SourceCodeRef mySourceCodeRef;
public:
typedef std::runtime_error Base;

Ex( SourceCodeRef const& ref, char const message[], int errorCode )
: Base( message ), myErrorCode( errorCode ), mySourceCodeRef( ref )
{}

virtual SourceCodeRef const& sourceCodeRef() const
{
return mySourceCodeRef;
}

virtual int errorCode() const
{
return myErrorCode;
}

class MacroHelper
{
private:
SourceCodeRef myRef;
public:
MacroHelper( SourceCodeRef const& ref ): myRef( ref ) {}
void doThrow( char const message[], int errorCode ) const
{
throw Ex( myRef, message, errorCode );
}
};
};

#define THROW( classname, arguments ) \
classname::MacroHelper( SOURCECODEREF ).doThrow arguments
What this does is to separate concerns.

To the above Ex-class I would perhaps add
virtual void doThrow() const { throw *this; }
for reasons unrelated to constructor argument-passing in a class hierarchy.
25 // throw removed
26 #define THROW(Class, Args) Class Args .doThrow(__FILE__, __LINE__)
27
28 int main()
29 {
30 try
31 {
32 THROW(Ex, ("blah", 1));
33 return EXIT_SUCCESS;
34 }
35 catch( std::exception const& )
36 {
37 return EXIT_FAILURE;
38 }
39 }

Now my project compiles.

But with this macro, the exception is allocated on the stack. And i don't
know for the throw case. Must i create a copy in the heap or is "throw
*this" ok?


The effect of throwing is as if the copy constructor is invoked to copy
the object. The compiler may optimize that away. But the upshot is that
throwing is logically by value, not by reference, so there is no problem.

--
A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 22 '05 #17
"TheDD" <pa*********@pas.de.spam.fr> wrote in message
On Sat, 15 May 2004 22:08:46 GMT, Siemel Naran wrote: if (bad)
throw Class(__FILE__, __FUNCTION__, __LINE__) << f("hello");

?
Yes, that's after the macro expansion.

Your original code was

#define THROW(Class, args...) throw Class(__FILE__, __LINE__, ## args)

Because you use the __FILE__ macros I suggest you keep it, but change it to

#define THROW(Class, args) throw Class(__FILE__, __LINE__) << args;

and instead of

THROW(ErrorClass, "hello", "world");

you say

THROW(ErrorClass, "hello" << world");

Now coming to think of it you could overload the comma operator, and then
one would write

THROW(ErrorClass, "hello" , world");

I think that's exactly what you asked for.

template <typename T, int N>
class args

Let's say i want to throw something:

if (bad)
throw Class(__FILE_, __FUNCTION__, __LINE__) << args<int, 0> +
args<string, "foo">;
The way I would approach it, is in stdafx.h or something typedef args<int,
0> to IntList. And then

THROW(IntList + 2 + 3);

Note all the objects must have the same type here. The boost library has
Variant types, and if I'm not mistaken another implementatino of Args that I
think overloads the comma operator, should you want to use it.
1/ I remember that string are difficult to use as template parameters.
2/ The code looks awful, is complicated for not much, facilitate
errors, and is probably slow (i don't manage to get when the arguments
evaluation occurs).
1) Not true.
2) It might look awful as you're not familiar with it. As for speed, there
should be none on a very optimizing compiler, but there may be some in
realistic compilers these days. I suspect it is very little. We should
measure to find the exact degradation. The ease of maintaince might
outweigh. Plus, people in this NG say exceptions aren't thrown often, and
besides much time is spent in stack unwinding and other things associated
with exceptions, so the extra time might still not be an issue.
The aim for the macro was to make it simple, clean and easily
readable. Thx a lot for your help and your time, i knwo "it's for
free", but your solution doesn't fit my needs.


In general, macro code is harder to maintain than template code.
Jul 22 '05 #18
TheDD wrote:
[...]


first, thx to all. Never too late, here is the system i'v choosen (based on
your solutions):

$ cat -n exceptions_.cc
1 #include <iostream>
2 #include <string>
3 #include <cassert>
4
5 #define THROW(Class, args) throw Class args << \
6 new Location(__FILE__, __LINE__)
7
8 class Location
9 {
10 public:
11 Location()
12 : file("--invalid--"), line(-1)
13 {
14 }
15
16 Location(const char * file, int line)
17 : file(file), line(line)
18 {
19 }
20
21 std::string file;
22 int line;
23 };
24
25 class Ex
26 {
27 protected:
28 Location loc;
29
30 public:
31 Ex()
32 {
33 }
34
35 virtual void dump(std::ostream & out) const
36 {
37 out << "Ex::dump()" << std::endl;
38 out << " * file = " << loc.file << std::endl;
39 out << " * line = " << loc.line << std::endl;
40 }
41
42 };
43
44 template <typename T>
45 class Ex_ : public Ex
46 {
47 public:
48 T & operator << (Location * loc)
49 {
50 this->loc = *loc;
51 delete loc;
52
53 T * real = dynamic_cast<T *>(this);
54 assert(real);
55 return *real;
56 }
57 };
58
59 class Ex2 : public Ex_<Ex2>
60 {
61 std::string msg;
62
63 public:
64 Ex2(const char * msg)
65 : msg(msg)
66 {
67 }
68
69 virtual void dump(std::ostream & out) const
70 {
71 Ex::dump(out);
72 out << "Ex2::dump()" << std::endl;
73 out << " * msg = " << msg << std::endl;
74 }
75 };
76
77 int
78 main()
79 {
80 try
81 {
82 THROW(Ex2, ("blah"));
83 }
84 catch (const Ex & ex)
85 {
86 ex.dump(std::cerr);
87 }
88
89 return 0;
90 }

$ g++-3.3.2 -W -Wall -std=c++98 -pedantic exceptions_.cc
exceptions_.cc:26: warning: `class Ex' has virtual functions but non-virtual
destructor
exceptions_.cc: In instantiation of `Ex_<Ex2>':
exceptions_.cc:60: instantiated from here
exceptions_.cc:46: warning: `class Ex_<Ex2>' has virtual functions but
non-virtual destructor
exceptions_.cc:60: warning: `class Ex2' has virtual functions but
non-virtual destructor
$ ./a.out
Ex::dump()
* file = exceptions_.cc
* line = 82
Ex2::dump()
* msg = blah
Ex_ is necessary to avoid loosing the real type in the << operator.

--
TheDD
Jul 22 '05 #19
TheDD <pa*********@pas.de.spam.fr> wrote in message news:<c9**********@news-reader4.wanadoo.fr>...
TheDD wrote:
[...]
first, thx to all. Never too late, here is the system i'v choosen (based on
your solutions):

$ cat -n exceptions_.cc
1 #include <iostream>
2 #include <string>
3 #include <cassert>
4
5 #define THROW(Class, args) throw Class args << \
6 new Location(__FILE__, __LINE__)

Why are you using new? Why not just:
throw Class args << Location(__FILE__, __LINE__) [redacted]
43
44 template <typename T>
45 class Ex_ : public Ex
46 {
47 public:
48 T & operator << (Location * loc) T& operator << (const Location& loc) 49 {
50 this->loc = *loc; this->loc = loc; 51 delete loc; // delete loc; // line not needed.
52
53 T * real = dynamic_cast<T *>(this);
54 assert(real);
55 return *real;
56 }
57 };
58
[redacted]

Jul 22 '05 #20
red floyd wrote:
Why are you using new? Why not just:
throw Class args << Location(__FILE__, __LINE__)
[redacted]
43
44 template <typename T>
45 class Ex_ : public Ex
46 {
47 public:
48 T & operator << (Location * loc)

T& operator << (const Location& loc)
49 {
50 this->loc = *loc;

this->loc = loc;
51 delete loc;

// delete loc; // line not needed.
52
53 T * real = dynamic_cast<T *>(this);
54 assert(real);
55 return *real;
56 }
57 };
58
[redacted]


thx, i've changed my code, but i used to think that in c++ you can't do:

obj.method(Class(args));

but

Class c(args);
obj.method(c);

so i thought i was the same in the case of << (don't understand why it's
not)

BTW, i don't know the rationale of that.

--
TheDD
Jul 22 '05 #21
"TheDD" <pa*********@pas.de.spam.fr> wrote...
red floyd wrote:
Why are you using new? Why not just:
throw Class args << Location(__FILE__, __LINE__)
[redacted]
43
44 template <typename T>
45 class Ex_ : public Ex
46 {
47 public:
48 T & operator << (Location * loc)

T& operator << (const Location& loc)
49 {
50 this->loc = *loc;

this->loc = loc;
51 delete loc;

// delete loc; // line not needed.
52
53 T * real = dynamic_cast<T *>(this);
54 assert(real);
55 return *real;
56 }
57 };
58
[redacted]


thx, i've changed my code, but i used to think that in c++ you can't do:

obj.method(Class(args));

but

Class c(args);
obj.method(c);

so i thought i was the same in the case of << (don't understand why it's
not)

BTW, i don't know the rationale of that.


Class(args) is a temporary. If your operator<< accepts a non-const
reference as its left operand, then you cannot say

Class(args) << blah

because binding a non-const reference to a temporary is prohibited.

Or maybe I am completely off and you're asking about something else,
then sorry for being too inattentive.

Victor
Jul 22 '05 #22
"TheDD" <pa*********@pas.de.spam.fr> wrote...
red floyd wrote:
Why are you using new? Why not just:
throw Class args << Location(__FILE__, __LINE__)
[redacted]
43
44 template <typename T>
45 class Ex_ : public Ex
46 {
47 public:
48 T & operator << (Location * loc)

T& operator << (const Location& loc)
49 {
50 this->loc = *loc;

this->loc = loc;
51 delete loc;

// delete loc; // line not needed.
52
53 T * real = dynamic_cast<T *>(this);
54 assert(real);
55 return *real;
56 }
57 };
58
[redacted]


thx, i've changed my code, but i used to think that in c++ you can't do:

obj.method(Class(args));

but

Class c(args);
obj.method(c);

so i thought i was the same in the case of << (don't understand why it's
not)

BTW, i don't know the rationale of that.


Class(args) is a temporary. If your operator<< accepts a non-const
reference as its left operand, then you cannot say

Class(args) << blah

because binding a non-const reference to a temporary is prohibited.

Or maybe I am completely off and you're asking about something else,
then sorry for being too inattentive.

Victor
Jul 22 '05 #23
Le 27/05/2004 à 04:18:11, Victor Bazarov <v.********@comAcast.net> a
écrit:
Class(args) is a temporary. If your operator<< accepts a non-const
reference as its left operand, then you cannot say

Class(args) << blah

because binding a non-const reference to a temporary is prohibited.
Thx for the tip
Or maybe I am completely off and you're asking about something else,
then sorry for being too inattentive.


Well, what about the right operand? Same rules apply?

--
TheDD
Jul 22 '05 #24
TheDD wrote:
Le 27/05/2004 à 04:18:11, Victor Bazarov <v.********@comAcast.net> a
écrit:

Class(args) is a temporary. If your operator<< accepts a non-const
reference as its left operand, then you cannot say

Class(args) << blah

because binding a non-const reference to a temporary is prohibited.

Thx for the tip

Or maybe I am completely off and you're asking about something else,
then sorry for being too inattentive.

Well, what about the right operand? Same rules apply?


Yes, however, it is customary to have the right operand of operator<<
a const reference anyway. Rarely is it needed to not have it const.

Victor
Jul 22 '05 #25
TheDD <pa*********@pas.de.spam.fr> wrote in message news:<na***************************@40tude.net>...
Le 27/05/2004 à 04:18:11, Victor Bazarov <v.********@comAcast.net> a
écrit:
Class(args) is a temporary. If your operator<< accepts a non-const
reference as its left operand, then you cannot say

Class(args) << blah

because binding a non-const reference to a temporary is prohibited.


Thx for the tip
Or maybe I am completely off and you're asking about something else,
then sorry for being too inattentive.


Well, what about the right operand? Same rules apply?


Yeah. Temps can only be thrown around via value or const reference.

What about

friend Ex_ operator<< (const Ex_&, const Location&)

(note that the return value is an Ex_, not an Ex_&!)
Jul 22 '05 #26
Le 27/05/2004 à 19:30:15, red floyd <re********@yahoo.com> a écrit:
TheDD <pa*********@pas.de.spam.fr> wrote in message news:<na***************************@40tude.net>...
Le 27/05/2004 à 04:18:11, Victor Bazarov <v.********@comAcast.net> a
écrit:
Class(args) is a temporary. If your operator<< accepts a non-const
reference as its left operand, then you cannot say

Class(args) << blah

because binding a non-const reference to a temporary is prohibited.


Thx for the tip
Or maybe I am completely off and you're asking about something else,
then sorry for being too inattentive.


Well, what about the right operand? Same rules apply?


Yeah. Temps can only be thrown around via value or const reference.

What about

friend Ex_ operator<< (const Ex_&, const Location&)

(note that the return value is an Ex_, not an Ex_&!)


I've tried something like that but the << operator can take only one
argument (it's the rationale for my Location class).

--
TheDD
Jul 22 '05 #27
TheDD wrote:
Le 27/05/2004 à 19:30:15, red floyd <re********@yahoo.com> a écrit:
What about

friend Ex_ operator<< (const Ex_&, const Location&)

(note that the return value is an Ex_, not an Ex_&!)

I've tried something like that but the << operator can take only one
argument (it's the rationale for my Location class).


That's only true if your operator << is a member. 'red floyd' showed
the declaration of a stand-alone operator <<, IIUIC.

V
Jul 22 '05 #28

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

Similar topics

10
by: Mac | last post by:
Is there a way to mimic the behaviour of C/C++'s preprocessor for macros? The problem: a lot of code like this: def foo(): # .... do some stuff if debug: emit_dbg_obj(DbgObjFoo(a,b,c)) #...
7
by: Michael B Allen | last post by:
If I define a variadic macro like say: #define PRINT(fmt, ...) _myprintf(__FILE__ ": " fmt, __VA_ARGS__) and I call this like: PRINT("no args"); the preprocessor generates:
11
by: No Such Luck | last post by:
I had a situation in a C program, which contained hundreds of calls to "fprintf (stdout, ...", where I needed to flush stdout immediately after any stream was sent there. More specifically, I...
17
by: ethan | last post by:
Hi All, How to write a macro with variable length of argument? For example, if i need a macro to check return value of printf. #define PRINTF_ESC(x, ...) if(printf(x, ...) == 10) goto end; ...
4
by: StdNewer | last post by:
#ifndef OF /* function prototypes */ # ifdef STDC # define OF(args) args # else # define OF(args) () # endif #endif void func OF( args );
5
by: Srinivas Mudireddy | last post by:
Hi, We have bunch of message levels and depending on whether that level is turned on, messages of that level are printed. For example, we have levels like MSG_LOW, MSG_MED etc. We want to...
7
by: Paul | last post by:
I would like to define a list of parameters, and then pass them to a macro. However, the compiler (gcc) only sees one parameter, rather than expanding the definition. Could anyone suggest a way of...
9
by: Two-Horned Unicorn | last post by:
The following code compiles and works as expected when compiled with gcc. /* empty-args.c */ #include <stdio.h> #define foo(x,y) puts("bar: x=\"" #x "\"; y=\"" #y "\"") #define bar(x) ...
6
by: JohnZ | last post by:
Hi, I'm trying to define a macro that calls a log function: #define LOG(level, device, pcString, args ...) if (level < SERIAL_LOG_LEVEL) _log(device, pcString, ## args) void _log (unsigned...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
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,...
0
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...
0
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...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

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.