Macro var args

T

TheDD

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
 
B

bartek

G

Gianni Mariani

TheDD said:
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 T0inline T DoThrow( T0 & a0 )
{
return T( file, line, a0 );
}

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

template <
typename T,
typename T0,
typename T1,
typename T2inline 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" );

}
 
V

Victor Bazarov

TheDD said:
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
 
T

TheDD

Victor said:
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.
 
S

Siemel Naran

#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).
 
T

TheDD

Siemel said:
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.info.Macro_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).
 
S

Siemel Naran

TheDD said:
Siemel Naran wrote: 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.
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);
}
};
 
A

Anil Mamede

TheDD said:
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
 
T

TheDD

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");

?
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.
 
A

Alf P. Steinbach

* TheDD said:
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.
 
T

TheDD

Alf said:
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.
 
A

Alf P. Steinbach

* TheDD said:
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?
 
T

TheDD

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



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 ;)
 
T

TheDD

TheDD said:
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?
 
T

TheDD

TheDD said:
[...]
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 :(
 
A

Alf P. Steinbach

* TheDD said:
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.
 
S

Siemel Naran

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.

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.
 
T

TheDD

TheDD said:

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::eek:stream & 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::eek:stream & 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.
 
R

red floyd

TheDD said:
TheDD said:

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]
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top