End-of-the-week fun

D

Dave

TGIF!!!

I don't know if people will be interested in this or not, but if so, we
might learn a few interesting tidbits!

What are some of the most obscure features of the language you know of?
Please exclude anything that's not strictly part of the standard, even if a
very common extension. This can be in the core language itself or in the
standard library.

In addition to the obscure feature, a reason for its existence, if known,
would also be very interesting to hear!

I'll throw out a couple:

1. Constructor and destructor names may be surrounded by parenthesis. i.e.
(~MyClass)( ) {...}

2. When trying to match an exception to a catch clause, user-defined
conversions via a one-argument constructor are not used. The short program
below prints "Point 2".

Unfortunately, I don't know the reasons for these. Item 1 may not have a
real compelling reason, but surely item 2 does. I'd be very interested to
hear the reason for this behavior if anybody knows...

#include <iostream>

using namespace std;

class foo_t
{
public:
foo_t(int) {}
(~foo_t)() {}
};

int main()
{
try
{
throw 45;
}
catch(foo_t)
{
cout << "Point 1" << endl;
}
catch(int)
{
cout << "Point 2" << endl;
}

return 0;
}
 
G

Gianni Mariani

Dave said:
TGIF!!!

I don't know if people will be interested in this or not, but if so, we
might learn a few interesting tidbits!

What are some of the most obscure features of the language you know of?
Please exclude anything that's not strictly part of the standard, even if a
very common extension. This can be in the core language itself or in the
standard library.

In addition to the obscure feature, a reason for its existence, if known,
would also be very interesting to hear!

I'll throw out a couple:

1. Constructor and destructor names may be surrounded by parenthesis. i.e.
(~MyClass)( ) {...}

2. When trying to match an exception to a catch clause, user-defined
conversions via a one-argument constructor are not used. The short program
below prints "Point 2".

Unfortunately, I don't know the reasons for these. Item 1 may not have a
real compelling reason,

Maybe it makes ut easier to parse templates (not even thought out idea)


but surely item 2 does. I'd be very interested to
hear the reason for this behavior if anybody knows...

This one is (I think) obvious.

consider this code.

try
{
polyobj->VirtFunc();

}
catch ( foo_t )
{
}
catch ( int )
{
}

Since the compiler has no idea what might get thrown
there is no way it will know which conversion funtion
to use - and some of the conversions may become
ambigous (at run-time) since there may be more
than one conversion and that's simply a bad idea.
 
R

Rob Williscroft

Dave wrote in
1. Constructor and destructor names may be surrounded by parenthesis.
i.e. (~MyClass)( ) {...}

#include <iostream>
#include <ostream>

#define macro(x) (std::cout << (x) << std::endl)

void (macro)( char const * x )
{
macro( x );
}

int (f(int i ))
{
return i + 1;
}

char const (*name) = "name";

int main()
{
using namespace std;

macro( f( 2 ) );
macro( "macro" );
#undef macro
macro( "function" );
macro( name );
}

Rob.
 
A

Andrey Tarasevich

Dave said:
TGIF!!!

I don't know if people will be interested in this or not, but if so, we
might learn a few interesting tidbits!

What are some of the most obscure features of the language you know of?
Please exclude anything that's not strictly part of the standard, even if a
very common extension. This can be in the core language itself or in the
standard library.

In addition to the obscure feature, a reason for its existence, if known,
would also be very interesting to hear!

I'll throw out a couple:

1. Constructor and destructor names may be surrounded by parenthesis. i.e.
(~MyClass)( ) {...}

2. When trying to match an exception to a catch clause, user-defined
conversions via a one-argument constructor are not used.

3. Normally in both C and C++ declaring an entity as 'int' is equivalent
to declaring it as 'signed int'. However, there is a context in both C
and C++ where 'int' might be equivalent to 'unsigned int'
(implementation defined). This context is: bit field declarations

struct S {
int i:5; // <- signed or unsigned - implementation defined
};

4. There is a context in C++ where parenthesis changes the semantical
meaning of an expression even though it doesn't alter the binding of
operators (defined by their precedence). This context is: taking the
address of a class data member

struct S {
int i;
};
...
&S::i; // <- this expression has type 'int (S::*)'
&(S::i); // <- this expression has type 'int*'

5. In constructor initializer lists data member names and their
respective initializers are looked up in different scopes, so that
there's no conflict between constructor parameter names and class data
member names

struct S {
int i;
S(int i) : i(i) // initializes ' ' with value of parameter 'i'
{}
};
 
D

Dave

Andrey Tarasevich said:
3. Normally in both C and C++ declaring an entity as 'int' is equivalent
to declaring it as 'signed int'. However, there is a context in both C
and C++ where 'int' might be equivalent to 'unsigned int'
(implementation defined). This context is: bit field declarations

struct S {
int i:5; // <- signed or unsigned - implementation defined
};

4. There is a context in C++ where parenthesis changes the semantical
meaning of an expression even though it doesn't alter the binding of
operators (defined by their precedence). This context is: taking the
address of a class data member

struct S {
int i;
};
...
&S::i; // <- this expression has type 'int (S::*)'
&(S::i); // <- this expression has type 'int*'

Interesting! The first expression has type pointer-to-member, but I'm
curious what an example is of how an expression of the second type would be
used... My compiler(VC++ 7.1) seems to choke on it!
 
A

Andrey Tarasevich

Dave said:
Interesting! The first expression has type pointer-to-member, but I'm
curious what an example is of how an expression of the second type would be
used... My compiler(VC++ 7.1) seems to choke on it!

The example I used is far from perfect. Sorry. In order to demonstrate
the difference I should have used a context where both expressions are valid

struct S {
int i;

void foo()
{
&S::i; // <- this expression has type 'int (S::*)'
&(S::i); // <- this expression has type 'int*'
}
};
 
A

Andrey Tarasevich

...
[1 - 5 skipped]
...

6. (This is straight from the standard and might be well known to some,
but anyway) Typedef names for function types can be used to declare both
regular and member functions

typedef void VVF();

VVF foo; // declares 'void foo()'

struct S
{
VVF bar; // declares 'void S::bar()'
};

Moreover, const-qualifier can be added to 'typedef'-ed type and used in
the following manner

typedef void VVFC() const;

struct S
{
VVFC bar(); // declares 'void bar() const'
};

This typedef-name cannot be used to declare non-member functions.

7. In most cases the type and value of the initializer expression in a
declaration does not depend on the type of the object being declared. In
a popular example

double d = 1/2;

the type of the expression '1/2' is 'int' and its value is '0', not
'double' and '0.5'. However, in certain contexts the type and value of
the expression might depend on the type of the object being initialized:

void foo();
void foo(int);

void (*p1)() = &foo;
// The initializer expression has type 'void (*)()' and it points
// to the first 'foo'

void (*p2)(int) = &foo; // the initializer has type 'void (*)(int)'
// The initializer expression has type 'void (*)(int)' and it points
// to the second 'foo'

The same applies to assignment and some other contexts.
 
R

Rolf Magnus

Andrey Tarasevich wrote:

[1 - 7 skipped]

8. Standard library: The standard class basic_ios provides a conversion
operator to void* that returns "some non-null pointer" (quoted from the
standard) if it's not in fail state or a null pointer if it is. It is
e.g. used in the famous:

while (input_stream >> some_variable)
{
// do something
}

There, operator>> returns a reference to the stream, which is then
converted to void* for the loop condition.
 
M

Moonlit

Hi,

Sswapping the array name and the subscript:

#include <iostream>

using namespace std;

int main()
{
char A[6];

memset( A, 0, sizeof A );
A[5] = 'I' ;
cerr << 5[A] << endl;

return 0;
}

Regards, Ron AF Greve
 
A

Agent Mulder

TGIF!!!
What are some of the most obscure features of the language you know of?
</>

Let the compiler do computations. The compiler:

#include<iostream>

template<int A>struct Factorial
{
enum{value=A*Factorial<A-1>::value};
};

struct Factorial<1>
{
enum{value=1};
};

int main()
{
Factorial<6>f;
cout<<f.value; //output 720 computed at compile time
return 0;
}

-X
 
D

Dave

I don't know if people will be interested in this or not, but if so, we
might learn a few interesting tidbits!

What are some of the most obscure features of the language you know of?
Please exclude anything that's not strictly part of the standard, even if a
very common extension. This can be in the core language itself or in the
standard library.

In addition to the obscure feature, a reason for its existence, if known,
would also be very interesting to hear!

I'll throw out a couple:

1. Constructor and destructor names may be surrounded by parenthesis. i.e.
(~MyClass)( ) {...}

2. When trying to match an exception to a catch clause, user-defined
conversions via a one-argument constructor are not used.

Another interesting item just occurred to me...

The example of what I'm about to mention is adapted from "C++ Templates, The
Complete Guide", bottom of page 44.

The class template std::bitset<> has a member function template named
to_string<>(). Consider this example of using this member function
template:

template<int N>
void printBitSet(const std::bitset<N> &bs)
{
std::cout << bs.template to_string<char, char_traits<char>,
allocator<char> >();
(); // This won't work!
}

The .template is necessary to tell the compiler that to_string is a
template. This is analagous to using typename to tell the compiler you're
specifying a type name. .template and typename are necessary when the
construct involved depends on a template parameter (in this case N).

Thanks for all of the interesting responses to my original post! Keep 'em
coming if more comes to mind!
 
D

Dave

I don't know if people will be interested in this or not, but if so, we
might learn a few interesting tidbits!

What are some of the most obscure features of the language you know of?
Please exclude anything that's not strictly part of the standard, even if a
very common extension. This can be in the core language itself or in the
standard library.

In addition to the obscure feature, a reason for its existence, if known,
would also be very interesting to hear!

Using protected inheritance to allow in-class polymorphism to be accessed
from a derived class:



#include <iostream>

using namespace std;

class base
{
public:
base() {cout << "base::base()" << endl;}
virtual ~base() {cout << "base::~base()" << endl;}
virtual void virt_func() {cout << "base::virt_func()" << endl;}
};

class derived: protected base
{
public:
derived() {cout << "derived::derived()" << endl;}
virtual ~derived() {cout << "derived::~derived()" << endl;}
virtual void virt_func() {cout << "derived::virt_func()" << endl;}
};

class most_derived: private derived
{
public:
most_derived() {cout << "most_derived::most_derived()" << endl;}
virtual ~most_derived() {cout << "most_derived::~most_derived()" <<
endl;}

void foo()
{
base *b(new derived);

b->virt_func();

delete b;
}
};

int main()
{
most_derived md;

md.foo();

return 0;
}
 

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