The C++ Programming Language, 4th Edition

Author: Bjarne Stroustrup
4.3
All Stack Overflow 10
This Year Stack Overflow 2
This Month Hacker News 1

The C++ Programming Language, 4th Edition

4.3

Review Date:

Comments

by anonymous   2018-03-19

To start with Bjarne Stroustrup in his 4th edition of his seminal book "The C++ Programming Language" doesn't refer to the use of auto as rendered in your code example. But rather to the standard use of the auto specifier as:

  • Specifier for variables where their type is going to be deduced by its initializer (e.g., auto i = 0;).
  • Specifier for function's return type where it's going to be deduced by its trailing return type or from its return statement.

    auto foo(int a, int b) {return a + b; }

In your example you're referring to the use of auto as a placeholder as suggested by C++ extensions for Concepts (N4674) proposal. Unfortunately, this is not standard C++ yet. It was to be accepted in C++17 but it didn't make it. Hopes now rise for C++20. However, use of auto like that is provided by GCC as an extension. Work on C++ concepts for GCC started very early, it even predates the advent of C++11. At some point work on concepts was abandoned and then restarted under another name namely Concepts Lite. Support back then was pretty unstable (e.g., GCC version 5.4). Thus, what you're experiencing is a GCC bug. In more recent versions of GCC this bug has been corrected.

by anonymous   2018-03-19

K&R and Stroustrup are classics, and eventually you should get them, but I don't think they are good introduction for C++ beginners. Thinking in modern C++ is thinking in classes, templates, exceptions, and streams, none of which available in C language.

I would recommend a college-level textbook on C++ like Deitel and Deitel. alt text http://ecx.images-amazon.com/images/I/61dECNkdnTL._SL500_AA240_.jpg

After playing around, you should focus on learning to write a class that behaves like a built-in class. That means providing a copy constructor, operator=, operator==, operator<<, etc.. Along the way you'll meet various concepts embedded in the language of C++. I would agree with others on Effective C++ is a must read once you are comfortable with the basics.

by anonymous   2017-08-20

The short version:

In COM you should use HRESULTs (and strive to use ISupportErrorInfo, etc.) for most/all types of error conditions. The HRESULT mechanism should be viewed as a form of exception throwing. If you are familiar with that, consider "Error conditions" as anything for which you would normally throw an exception in a language that supports them. Use custom return values for things for which you would not normally use exceptions.

For example, use a failure HRESULT for invalid parameters, invalid sequence of operations, network failures, database errors, unexpected conditions such as out-of-memory, etc. On the other hand, use custom out parameters for things like 'polling, data is not ready yet', EOF conditions, maybe 'checked data and it doesn't pass validations'. There is plenty of discussions out there discussing what each should be (e.g. Stroustrup's TC++PL). The specifics will heavily depend on your particular object's semantics.

The longer version:

At a fundamental level, the COM HRESULT mechanism is just an error code mechanism which has been standardized by the infrastructure. This is mostly because COM must support a number of features such as inter-process (DCOM) and inter-threaded (Apartments) execution, system managed services (COM+), etc. The infrastructure has a need to know when something has failed, and it has a need to communicate to both sides its own infrastructure-related errors. Everybody needs to agree on how to communicate errors.

Each language and programmer has a choice of how to present or handle those errors. In C++, we typically handle the HRESULTs as error codes (although you can translate them into exceptions if you prefer error handling that way). In .NET languages, failure HRESULTs are translated into exceptions because that's the preferred error mechanism in .NET.

VB6 supports "either". Now, I know VB6's so-called exception handling has a painful syntax and limited scoping options for handlers, but you don't have to use it if you don't want to. You can always use ON ERROR RESUME NEXT and do it by hand if you think the usage pattern justifies it in a specific situation. It's just that instead of writing something like this:

statusCode = obj.DoSomething(param1)
If IS_FAILURE(statusCode) Then
    'handle error
End If

Your write it like this:

ON ERROR RESUME NEXT
...
obj.DoSomething param1
IF Error.Number <> 0 Then
    'handle error
End If

VB6 is simply hiding the error code return value from the method call (and allowing the object's programmer to substitute it for a "virtual return value" via [retval]).

If you make up your own error reporting mechanism instead of using HRESULTs, you will:

  1. Spend a lot of time reinventing a rich error reporting mechanism that will probably mirror what ISupportsErrorInfo already gives you (or most likely, not provide any rich error information).
  2. Hide the error status from COM's infrastructure (which might or might not matter).
  3. Force your VB6 clients to make one specific choice out of the two options they have: they must do explicit line-by-line check, or more likely just ignore the error condition by mistake, even if they would prefer an error handler.
  4. Force your (say) C# clients to handle your errors in ways that runs contrary to the natural style of the language (to have to check every method call explicitly and... likely throw an exception by hand).
by anonymous   2017-08-20

One of the best explanation of lambda expression is given from author of C++ Bjarne Stroustrup in his book ***The C++ Programming Language*** chapter 11 (ISBN-13: 978-0321563842):

What is a lambda expression?

A lambda expression, sometimes also referred to as a lambda function or (strictly speaking incorrectly, but colloquially) as a lambda, is a simplified notation for defining and using an anonymous function object. Instead of defining a named class with an operator(), later making an object of that class, and finally invoking it, we can use a shorthand.

When would I use one?

This is particularly useful when we want to pass an operation as an argument to an algorithm. In the context of graphical user interfaces (and elsewhere), such operations are often referred to as callbacks.

What class of problem do they solve that wasn't possible prior to their introduction?

Here i guess every action done with lambda expression can be solved without them, but with much more code and much bigger complexity. Lambda expression this is the way of optimization for your code and a way of making it more attractive. As sad by Stroustup :

effective ways of optimizing

Some examples

via lambda expression

void print_modulo(const vector<int>& v, ostream& os, int m) // output v[i] to os if v[i]%m==0
{
    for_each(begin(v),end(v),
        [&os,m](int x) { 
           if (x%m==0) os << x << '\n';
         });
}

or via function

class Modulo_print {
         ostream& os; // members to hold the capture list int m;
     public:
         Modulo_print(ostream& s, int mm) :os(s), m(mm) {} 
         void operator()(int x) const
           { 
             if (x%m==0) os << x << '\n'; 
           }
};

or even

void print_modulo(const vector<int>& v, ostream& os, int m) 
     // output v[i] to os if v[i]%m==0
{
    class Modulo_print {
        ostream& os; // members to hold the capture list
        int m; 
        public:
           Modulo_print (ostream& s, int mm) :os(s), m(mm) {}
           void operator()(int x) const
           { 
               if (x%m==0) os << x << '\n';
           }
     };
     for_each(begin(v),end(v),Modulo_print{os,m}); 
}

if u need u can name lambda expression like below:

void print_modulo(const vector<int>& v, ostream& os, int m)
    // output v[i] to os if v[i]%m==0
{
      auto Modulo_print = [&os,m] (int x) { if (x%m==0) os << x << '\n'; };
      for_each(begin(v),end(v),Modulo_print);
 }

Or assume another simple sample

void TestFunctions::simpleLambda() {
    bool sensitive = true;
    std::vector<int> v = std::vector<int>({1,33,3,4,5,6,7});

    sort(v.begin(),v.end(),
         [sensitive](int x, int y) {
             printf("\n%i\n",  x < y);
             return sensitive ? x < y : abs(x) < abs(y);
         });


    printf("sorted");
    for_each(v.begin(), v.end(),
             [](int x) {
                 printf("x - %i;", x);
             }
             );
}

will generate next

0

1

0

1

0

1

0

1

0

1

0 sortedx - 1;x - 3;x - 4;x - 5;x - 6;x - 7;x - 33;

[] - this is capture list or lambda introducer: if lambdas require no access to their local environment we can use it.

Quote from book:

The first character of a lambda expression is always [. A lambda introducer can take various forms:

[]: an empty capture list. This implies that no local names from the surrounding context can be used in the lambda body. For such lambda expressions, data is obtained from arguments or from nonlocal variables.

[&]: implicitly capture by reference. All local names can be used. All local variables are accessed by reference.

[=]: implicitly capture by value. All local names can be used. All names refer to copies of the local variables taken at the point of call of the lambda expression.

[capture-list]: explicit capture; the capture-list is the list of names of local variables to be captured (i.e., stored in the object) by reference or by value. Variables with names preceded by & are captured by reference. Other variables are captured by value. A capture list can also contain this and names followed by ... as elements.

[&, capture-list]: implicitly capture by reference all local variables with names not men- tioned in the list. The capture list can contain this. Listed names cannot be preceded by &. Variables named in the capture list are captured by value.

[=, capture-list]: implicitly capture by value all local variables with names not mentioned in the list. The capture list cannot contain this. The listed names must be preceded by &. Vari- ables named in the capture list are captured by reference.

Note that a local name preceded by & is always captured by reference and a local name not pre- ceded by & is always captured by value. Only capture by reference allows modification of variables in the calling environment.

Additional

Lambda expression format

enter image description here

Additional references:

by anonymous   2017-08-20

Unfortunately, no such function exists in the C++ standard library.

If you do have access to Boost, then boost::numeric_cast should do exactly what you want. It will perform a conversion between two numeric types unless the conversion would go outside the range of the target type. In such cases, a boost::numeric::bad_numeric_cast exception is thrown.


If you were curious about implementing your own conversion, you can take a look at The C++ Programming Language 4th Edition by Bjarne Stroustrup (ISBN 978-0321563842).

In Chapter 11.5, he defines a narrow_cast as such:

template<class Target, class Source>
Target narrow_cast(Source v)
{
   auto r = static_cast<Target>(v); // convert the value to the target type
   if (static_cast<Source>(r)!=v)
      throw runtime_error("narrow_cast<>() failed");
   return r;
}

This implementation is quite bare and doesn't go quite as far as Boost's does, but could conceivably be modified to suit your needs.