Tuesday, June 16, 2015

Digest for comp.lang.c++@googlegroups.com - 25 updates in 8 topics

Paul <pepstein5@gmail.com>: Jun 16 12:12PM -0700

I tried the problem of generating solutions like 123 - 45 - 67 + 89 = 100. The point is that we get 100 and we use the digits from 1 to 9 in consecutive order.
My code is really ugly, and it also took me ages to do. Any insights on how I can improve it? The problem is stated more accurately in the initial comments.
Many thanks for your help.
 
Paul
 
/*Problem 5
Write a program that outputs all possibilities to put + or - or nothing between the numbers 1, 2, ..., 9 (in this order)
such that the result is always 100. For example: 1 + 2 + 34 - 5 + 67 - 8 + 9 = 100.*/
 
// First a utility function that inserts + and - into a vector of numbers to get a result
int insertSigns (const std::vector<int>& numbers, const std::string& plusesAndMinuses)
{
if(numbers.empty())
return 0;
 
int result = numbers[0];
for(int i = 1; i < numbers.size(); ++i)
result += (plusesAndMinuses[i - 1] == '+' ? numbers[i] : -numbers[i]);
 
return result;
}
 
// Generate all combinations of plus/minus signs of a given length. Use recursion
std::vector<std::string> plusesAndMinuses(int n)
{
std::vector<std::string> results;
 
if(!n)
return results;
 
if(n == 1)
return {"+", "-"};
 
const std::vector<std::string> formerResults = plusesAndMinuses(n-1);
 
for(int i = 0; i < formerResults.size(); ++i)
{
results.push_back("+" + formerResults[i]);
results.push_back("-" + formerResults[i]);
}
 
return results;
}
 
// Generate all vectors of numbers that can arise from concatenations in a list of numbers
// Numbers can only be concatenated with their neighbours. Use recursion
std::vector<std::vector<int>> concatenation (const std::vector<int>& numbers, int base = 10)
{
if(numbers.size() <= 1)
return {numbers};
 
const std::vector<int> tail(++numbers.begin(), numbers.end());
const std::vector<std::vector<int>> concatenateTail = concatenation(tail, base);
std::vector<std::vector<int> > results;
 
for(int i = 0; i < concatenateTail.size(); ++i)
{
std::vector<int> newVec;
newVec.push_back(concatenate(numbers[0], concatenateTail[i][0]));
for(int j = 1; j < concatenateTail[i].size(); ++j)
newVec.push_back(concatenateTail[i][j]);
 
results.push_back(newVec);
 
newVec.clear();
newVec.push_back(numbers[0]);
for(int j = 0; j < concatenateTail[i].size(); ++j)
newVec.push_back(concatenateTail[i][j]);
 
results.push_back(newVec);
}
 
return results;
}
 
// Investigates whether a number can be obtained from concatenation of a given vector
// Keeps track of all +, - sequences and concatenations which work.
void findSequences (int numberObtained, const std::vector<int>& numbers, std::vector<std::string>& plusMinus, std::vector<std::vector<int>>& sequences, int base = 10)
{
plusMinus.clear();
sequences.clear();
 
auto collection = concatenation(numbers, base);
for(const auto& vec : collection)
{
const auto& signs = plusesAndMinuses(vec.size() - 1);
for(auto& str : signs)
if(insertSigns(vec, str) == numberObtained)
{
plusMinus.push_back(str);
sequences.push_back(vec);
}
}
 
}
 
// Display the above result
void display(int numberObtained, const std::vector<std::string>& plusMinus, const std::vector<std::vector<int>>& sequences)
{
if(plusMinus.empty())
std::cout << std::endl << numberObtained << " can not be obtained. ";
 
for(int i = 0; i < plusMinus.size(); ++i)
{
std::cout << std::endl;
std::cout << sequences[i][0];
for(int j = 0; j < plusMinus[i].length(); ++j)
std::cout << " " << plusMinus[i][j] << " " << sequences[i][j + 1];
 
std::cout << " = " << numberObtained << std::endl;
}
}
 
// Combining above steps to calculate and then display results.
void display(int numberObtained, const std::vector<int>& numbers, int base = 10)
{
std::vector<std::string> plusMinus;
std::vector<std::vector<int> > results;
findSequences(numberObtained, numbers, plusMinus, results, base);
 
display(numberObtained, plusMinus, results);
}
 
// Test with given input.
void testProblem5()
{
std::vector<int> testVec;
for(int i = 1; i < 10; ++i)
testVec.push_back(i);
 
const int numberObtained = 100;
display(numberObtained, testVec);
}
Paul <pepstein5@gmail.com>: Jun 16 12:20PM -0700

On Tuesday, June 16, 2015 at 8:12:30 PM UTC+1, Paul wrote:
> My code is really ugly, and it also took me ages to do. Any insights on how I can improve it? The problem is stated more accurately in the initial comments.
> Many thanks for your help.
 
> Paul
 
Sorry, I left off the concatenate function. There's also a bug so that, contrary to what I claim, it won't work with bases other than 10. I'll repost the whole thing, fixing that bug.
 
// Concatenating numbers
int concatenate(int x, int y, int base = 10)
{
for(int i = 0; i < numDigits(y, base); ++i)
x *= base;
 
return x + y;
}
 
/*Problem 5
Write a program that outputs all possibilities to put + or - or nothing between the numbers 1, 2, ..., 9 (in this order)
such that the result is always 100. For example: 1 + 2 + 34 - 5 + 67 - 8 + 9 = 100.*/
 
// First a utility function that inserts + and - into a vector of numbers to get a result
int insertSigns (const std::vector<int>& numbers, const std::string& plusesAndMinuses)
{
if(numbers.empty())
return 0;
 
int result = numbers[0];
for(int i = 1; i < numbers.size(); ++i)
result += (plusesAndMinuses[i - 1] == '+' ? numbers[i] : -numbers[i]);
 
return result;
}
 
// Generate all combinations of plus/minus signs of a given length. Use recursion
std::vector<std::string> plusesAndMinuses(int n)
{
std::vector<std::string> results;
 
if(!n)
return results;
 
if(n == 1)
return {"+", "-"};
 
const std::vector<std::string> formerResults = plusesAndMinuses(n-1);
 
for(int i = 0; i < formerResults.size(); ++i)
{
results.push_back("+" + formerResults[i]);
results.push_back("-" + formerResults[i]);
}
 
return results;
}
 
// Generate all vectors of numbers that can arise from concatenations in a list of numbers
// Numbers can only be concatenated with their neighbours. Use recursion
std::vector<std::vector<int>> concatenation (const std::vector<int>& numbers, int base = 10)
{
if(numbers.size() <= 1)
return {numbers};
 
const std::vector<int> tail(++numbers.begin(), numbers.end());
const std::vector<std::vector<int>> concatenateTail = concatenation(tail, base);
std::vector<std::vector<int> > results;
 
for(int i = 0; i < concatenateTail.size(); ++i)
{
std::vector<int> newVec;
newVec.push_back(concatenate(numbers[0], concatenateTail[i][0], base));
for(int j = 1; j < concatenateTail[i].size(); ++j)
newVec.push_back(concatenateTail[i][j]);
 
results.push_back(newVec);
 
newVec.clear();
newVec.push_back(numbers[0]);
for(int j = 0; j < concatenateTail[i].size(); ++j)
newVec.push_back(concatenateTail[i][j]);
 
results.push_back(newVec);
}
 
return results;
}
 
// Investigates whether a number can be obtained from concatenation of a given vector
// Keeps track of all +, - sequences and concatenations which work.
void findSequences (int numberObtained, const std::vector<int>& numbers, std::vector<std::string>& plusMinus, std::vector<std::vector<int>>& sequences, int base = 10)
{
plusMinus.clear();
sequences.clear();
 
auto collection = concatenation(numbers, base);
for(const auto& vec : collection)
{
const auto& signs = plusesAndMinuses(vec.size() - 1);
for(auto& str : signs)
if(insertSigns(vec, str) == numberObtained)
{
plusMinus.push_back(str);
sequences.push_back(vec);
}
}
 
}
 
// Display the above result
void display(int numberObtained, const std::vector<std::string>& plusMinus, const std::vector<std::vector<int>>& sequences)
{
if(plusMinus.empty())
std::cout << std::endl << numberObtained << " can not be obtained. ";
 
for(int i = 0; i < plusMinus.size(); ++i)
{
std::cout << std::endl;
std::cout << sequences[i][0];
for(int j = 0; j < plusMinus[i].length(); ++j)
std::cout << " " << plusMinus[i][j] << " " << sequences[i][j + 1];
 
std::cout << " = " << numberObtained << std::endl;
}
}
 
// Combining above steps to calculate and then display results.
void display(int numberObtained, const std::vector<int>& numbers, int base = 10)
{
std::vector<std::string> plusMinus;
std::vector<std::vector<int> > results;
findSequences(numberObtained, numbers, plusMinus, results, base);
 
display(numberObtained, plusMinus, results);
}
 
// Test with given input.
void testProblem5()
{
std::vector<int> testVec;
for(int i = 1; i < 10; ++i)
testVec.push_back(i);
 
const int numberObtained = 100;
display(numberObtained, testVec);
}
Melzzzzz <mel@zzzzz.com>: Jun 16 04:51PM +0200

Problem is this:
 
void f(void*p){ // c callback
int i = (int)p;
...
}
 
but this gives error when p is 64 bit and int 32 bit.
I can cast to long but long does not have to be 64 bit,either.
What do you suggest?
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 16 11:03AM -0400

On 6/16/2015 10:51 AM, Melzzzzz wrote:
 
> but this gives error when p is 64 bit and int 32 bit.
> I can cast to long but long does not have to be 64 bit,either.
> What do you suggest?
 
I suggest the type that can contain the value. The standard does not
provide a type that fits, leaving it to the implementation. If 'long'
is not large enough, use 'long long'.
 
Usually you need to write some implementation-specific conditionally
compiled code with typedefs producing the needed types, like
 
#if WIN32
typedef long integraltypeforstoringpointers;
#elif WIN64
typedef long long integraltypeforstoringpointers;
#elif ...
...
 
 
So, then you use that type to cast. But please don't use C-style casts,
use 'reinterpret_cast', that's exactly what it's for. E.g.:
 
integraltypeforstoringpointers i
= reinterpret_cast<integraltypeforstoringpointers>(p);
 
and the length of the statement and type name should be a warning that
you are doing something a bit unusual, and anybody who reads the code
needs to pay attention.
 
V
--
I do not respond to top-posted replies, please don't ask
Robert Wessel <robertwessel2@yahoo.com>: Jun 16 11:15AM -0500


>but this gives error when p is 64 bit and int 32 bit.
>I can cast to long but long does not have to be 64 bit,either.
>What do you suggest?
 
 
intptr_t and/or uintptr_t from cstdint. Although they don't
have to exist.
scott@slp53.sl.home (Scott Lurndal): Jun 16 04:28PM


>but this gives error when p is 64 bit and int 32 bit.
>I can cast to long but long does not have to be 64 bit,either.
>What do you suggest?
 
use the type 'uintptr_t' (C++11 and later)
legalize+jeeves@mail.xmission.com (Richard): Jun 16 05:47PM

[Please do not mail me a copy of your followup]
 
Robert Wessel <robertwessel2@yahoo.com> spake the secret code
 
>intptr_t and/or uintptr_t from cstdint. Although they don't
>have to exist.
 
It's kinda annoying that these are optional.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
Melzzzzz <mel@zzzzz.com>: Jun 16 08:11PM +0200

On Tue, 16 Jun 2015 11:03:44 -0400
 
> I suggest the type that can contain the value. The standard does not
> provide a type that fits, leaving it to the implementation. If
> 'long' is not large enough, use 'long long'.
 
Well, this is actually int passed as void*. Because of C interface
generic parameter is void*. So I have to convert int -> void* -> int
Melzzzzz <mel@zzzzz.com>: Jun 16 08:16PM +0200

On Tue, 16 Jun 2015 11:15:23 -0500
> >What do you suggest?
 
> intptr_t and/or uintptr_t from cstdint. Although they don't
> have to exist.
 
Too ,bad ;(
I need intptr_t as conversion is actually passing int parameter as void*
and than back to int.
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 16 02:21PM -0400

On 6/16/2015 2:11 PM, Melzzzzz wrote:
>> 'long' is not large enough, use 'long long'.
 
> Well, this is actually int passed as void*. Because of C interface
> generic parameter is void*. So I have to convert int -> void* -> int
 
Read about 'reinterpret_cast' in your compiler documentation and see
what limitations it sets. Please don't use a C-style cast, it's ugly,
dangerous, difficult to search for if you want to know where in your
code you're using it.
 
V
--
I do not respond to top-posted replies, please don't ask
legalize+jeeves@mail.xmission.com (Richard): Jun 16 07:01PM

[Please do not mail me a copy of your followup]
 
Melzzzzz <mel@zzzzz.com> spake the secret code
>> 'long' is not large enough, use 'long long'.
 
>Well, this is actually int passed as void*. Because of C interface
>generic parameter is void*. So I have to convert int -> void* -> int
 
An alternative is to pass a pointer to the int instead of the int.
 
Generally these C apis with void* context parameters are intending
that you allocate a chunk of memory and pass the pointer around to
the callbacks instead of raw values. This is more portable than
trying to figure out how to convert between int and void*. Any
pointer is implicitly convertible to a void* and you can static_cast
any void* to a pointer of type T (although the result is undefined
behavior of the void* didn't come from a pointer to type T).
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 16 03:14PM -0400

On 6/16/2015 3:01 PM, Richard wrote:
> pointer is implicitly convertible to a void* and you can static_cast
> any void* to a pointer of type T (although the result is undefined
> behavior of the void* didn't come from a pointer to type T).
 
Allocation of a plain int is often expensive in both memory and time,
and besides, who owns that pointer and who's going to deallocate that
memory when it's not needed anymore? What if a C API call happens
periodically with the same value, do you propose to allocate it every
time and deallocate after the call has returned? What if API is such
that it needs to retain the value for a few calls? A literal would be
much less trouble than managing the lifetime of a single 'int'.
 
Not saying that such a solution is unacceptable, just that it's not
necessarily easy or as clean as it might appear at a first glance.
 
V
--
I do not respond to top-posted replies, please don't ask
Noob <root@127.0.0.1>: Jun 16 08:47PM +0200

On 15/06/2015 16:35, Richard wrote:
 
 
>> int array[20] = { 0 };
 
> Value initialization:
> <http://en.cppreference.com/w/cpp/language/value_initialization>
 
I don't see the syntax suggested by Christian (type field_name = init_val;)
in cppreference's grammar?
 
I wrote the following test program:
 
class foo {
public:
int i = 5;
int array[5] = { 1, 2, 3 };
int uninit[100];
};
 
int main(void)
{
foo xx;
foo *yy = new foo;
foo *zz = new foo{};
foo *tt = new foo[20]{};
return xx.i + yy->i + zz->i + tt->i;
}
 
$ g++ -std=c++11 -Wall -Wextra -ggdb3 init.cpp
 
(I note that c++11 support was considered incomplete and experimental
in gcc 4.8)
 
The "uninit" array seems to be initialized to 0 in all cases
except xx. Is that by design or an accident of the allocator's
design?
 
What is the difference between new foo; and new foo{}; ?
 
Regards.
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 16 02:59PM -0400

On 6/16/2015 2:47 PM, Noob wrote:
>[..]
> What is the difference between new foo; and new foo{}; ?
 
'new foo' default-initializes the object, 'new foo{}' performs the so
called direct-initialization. They differ a bit. The one without the
braces looks for a c-tor that can be called without the arguments, and
if found, calls it. If none exist, it leaves the object uninitialized!
The form with braces default-initializes the object, which in absence of
any c-tors yet with member initializers, performs member-wise
initialization using the initializers provided for each member.
 
IOW, 'new foo' ignores the individuals member initializers while 'new
foo{}' uses those.
 
V
--
I do not respond to top-posted replies, please don't ask
legalize+jeeves@mail.xmission.com (Richard): Jun 16 07:04PM

[Please do not mail me a copy of your followup]
 
Noob <root@127.0.0.1> spake the secret code
>> <http://en.cppreference.com/w/cpp/language/value_initialization>
 
>I don't see the syntax suggested by Christian (type field_name = init_val;)
>in cppreference's grammar?
 
<http://en.cppreference.com/w/cpp/language/data_members>
 
 
>The "uninit" array seems to be initialized to 0 in all cases
>except xx. Is that by design or an accident of the allocator's
>design?
 
This is probably coming from the allocator and the fact that in your
small program you haven't released any previously allocated memory back
to the allocator for reuse. All memory obtained from the operating
system (in modern operating systems, anyway) is zeroed before being
given to the allocator in the C++ runtime.
 
>What is the difference between new foo; and new foo{}; ?
 
They both invoke the default constructor, so I'd say nothing.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
Doug Mika <dougmmika@gmail.com>: Jun 16 10:43AM -0700

I have heard of having operator+ inside a class, to define the + operation on objects of that class. However, what if we have defined such an operator outside of any class(and on top of that we make it a template)? And, what is the purpose of -> and what it points to in:
 
template<class T, class U>
auto operator+(const Matrix<T>& a, const Matrix<U>& b) -> Matrix<decltype(T{}+U{})> {
Matrix<decltype(T{}+U{})> res;
for (int i=0; i!=a.rows(); ++i)
for (int j=0; j!=a.cols(); ++j)
res(i,j) += a(i,j) + b(i,j);
return res;
}
legalize+jeeves@mail.xmission.com (Richard): Jun 16 06:03PM

[Please do not mail me a copy of your followup]
 
Doug Mika <dougmmika@gmail.com> spake the secret code
 
>template<class T, class U>
>auto operator+(const Matrix<T>& a, const Matrix<U>& b) ->
>Matrix<decltype(T{}+U{})> {
 
See item (2): <http://en.cppreference.com/w/cpp/language/auto>
 
A template function often wants to say "my return type is the type
resulting from some expression; dear compiler please figure that out
for me".
 
The mechanism for supporting this in C++11 is to declare the return
type of the template function "auto" and then use -> to specify the
return type with decltype.
<http://en.cppreference.com/w/cpp/language/decltype>
 
The "trailing return type" syntax can also be used with any function
declaration, not just template functions. See
<http://en.cppreference.com/w/cpp/language/function>
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
Doug Mika <dougmmika@gmail.com>: Jun 16 08:49AM -0700

On Monday, June 15, 2015 at 4:30:15 PM UTC-5, Richard wrote:
> The Computer Graphics Museum <http://computergraphicsmuseum.org>
> The Terminals Wiki <http://terminals.classiccmp.org>
> Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
 
Well, I had a look at the link you provided, I have actually seen it before, but it's not something I understand. Is there any chance that someone could quickly, in laymen terms, explain why the following function can be constexpr if it has a run-time variable as a parameter? And it's even allowed to call itself?
 
constexpr int fac(int n) { return (n<2)?1:n*fac(n-1); }
Bo Persson <bop@gmb.dk>: Jun 16 06:14PM +0200

On 2015-06-16 17:49, Doug Mika wrote:
>> value for n as some integral type constant or constant expression.
 
> Well, I had a look at the link you provided, I have actually seen it before, but it's not something I understand. Is there any chance that someone could quickly, in laymen terms, explain why the following function can be constexpr if it has a run-time variable as a parameter? And it's even allowed to call itself?
 
> constexpr int fac(int n) { return (n<2)?1:n*fac(n-1); }
 
It is constexpr if the parameter is known at compile time, like if it is
itself constexpr or a literal. In that case the compiler is required to
compute the value during compilation. And the result can be used as a
constant.
 
This doesn't in any way stop you from ALSO using the same function with
a non-const parameter, but of course then it will be evaluated at runtime.
 
 
Bo Persson
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 16 12:14PM -0400

On 6/16/2015 11:49 AM, Doug Mika wrote:
> [...]Is there any chance that someone could quickly, in laymen
> terms,
explain why the following function can be constexpr if it has a run-time
variable as a parameter? And it's even allowed to call itself?
 
> constexpr int fac(int n) { return (n<2)?1:n*fac(n-1); }
 
Write a small main program:
 
int main(int argc, char *argv[]) {
constexpr int fac10 = fac(10);
}
 
Is it OK? Now change the call to 'fac' to use not a constant by some
run-time variable, like 'argc'. Is it still OK?
 
Declaration of a function as 'constexpr' makes (a) the function itself
inline, and (b) allows the function to be called in an expression that
is expected to be 'const'. If the expression is not 'const', then
'constexpr' is simply ignored, I think. For instance, you can't do
 
constexpr int fac_argc = fac(argc);
// not allowed - 'argc' is not const
 
but it's totally OK to do
 
int fac_argc = fac(argc);
 
in which case 'constexpr' doesn't matter.
 
V
--
I do not respond to top-posted replies, please don't ask
Marcel Mueller <news.5.maazl@spamgourmet.org>: Jun 16 06:29PM +0200

On 15.06.15 20.52, Richard wrote:
> Cross-compilation and "not yet compiled" have nothing to do with
> constexpr and static_assert.
 
Well, constexpr forces a function to be deterministic, side effect free
and compile time evaluable. Although the exact definition depends on the
C++ standard version and includes some other constraints to ensure that
it can be evaluated. The newer the standard the more is allowed. From my
point of view this has to do with compilation.
 
Marcel
legalize+jeeves@mail.xmission.com (Richard): Jun 16 05:38PM

[Please do not mail me a copy of your followup]
 
Marcel Mueller <news.5.maazl@spamgourmet.org> spake the secret code
>C++ standard version and includes some other constraints to ensure that
>it can be evaluated. The newer the standard the more is allowed. From my
>point of view this has to do with compilation.
 
Again, this has nothing to do with "not yet compiled" and cross-compilation.
 
Cross-compilation is compiling source code on one architecture that
targets another architecture other than that which is hosting the
compiler. This has nothing to do with constexpr.
 
You don't even state precisely what you mean by "not yet compiled", so
there isn't anything more to be said about that. If you mean that a
constexpr function must be *defined* (and not just declared) in order
to be called as part of constructing a larger constant expression,
that is true.
 
A function can be declared constexpr, but not yet defined in the
current translation unit, and still be used to generate a value at
runtime.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
legalize+jeeves@mail.xmission.com (Richard): Jun 16 02:18PM

[Please do not mail me a copy of your followup]
 
fl <rxjwg98@gmail.com> spake the secret code
> BaseConstructor(int=0)
> {}
>};
 
Didn't we already go over this in another thread?
 
It feels like a bunch of people are taking a summer course in C++ using
a confusing and poorly written book and the instructor has recommended
you come here for help.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
scott@slp53.sl.home (Scott Lurndal): Jun 16 09:54AM -0600

>> extended types, and where they have, they are often not portable (there
>> is no guarantee that any of the exact types exist on a platform)
 
>Can you back that assertion up with any facts at all?
 
Probably not. Most of the C++ code that I've worked on over the
last 20+ years uses these types (before they were standardized,
and with names like u32, uint32, uint32_t etc).
 
Granted most of that code ran sans OS (it was the OS), and required
fixed types to map to various hardware registers.
 
However, absent API requirements for other types, I would prefer
using types for which I understand the characteristics in all
conditions, thus I prefer the explicitly sized types. Having
run into many issues in the past porting software from 16-bit
ints to 32-bit ints (and from 32-bit longs to 64-bit longs),
I would never advocating using 'int' for anything.
 
 
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
ram@zedat.fu-berlin.de (Stefan Ram): Jun 16 05:02AM

>B a[ 2 ];
>a[ 1 ].~B(); new( a + 1 )D(); // destroy old a[ 1 ] and place new a[ 1 ]
>Why does this now still has undefined behavior?
 
It seems that 3.8 deals with this and does only allow an
object of exactly the same class to be placed at this storage.
 
However, I found this in 9.5p4:
 
»If M has a non-trivial destructor and N has a
non-trivial constructor (for instance, if they declare
or inherit virtual functions), the active member of u
can be safely switched from m to n using the destructor
and placement new operator as follows:
 
u.m.~M();
new (&u.n) N;«
 
This is looking very close to what I do, but then it doesn't
really help me, because the information about which member is
active is not available at run time.
 
I could store this information myself, but this would mean
to /reinvent/ polymorphism, while I want to /use/ the
polymorphism of the language.
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: