Read two specific lines from text file and doing arithmetic process between them.

Pages: 12
Thomas1965 wrote:
Can you show me an example where the compiler isn't able to warn you?


http://stackoverflow.com/questions/2712076/how-to-use-an-iterator/2712125#2712125

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <vector>
#include <cmath>
#include <iostream>

using namespace std;
typedef struct point {
    float x;
    float y;
} point;

float distance(point *p1, point *p2)
{
    return sqrt((p1->x - p2->x)*(p1->x - p2->x) +
                (p1->y - p2->y)*(p1->y - p2->y));
}

int main()
{
    vector <point> po;
    point p1; p1.x = 0; p1.y = 0;
    point p2; p2.x = 1; p2.y = 1;
    po.push_back(p1);
    po.push_back(p2);

    vector <point>::iterator ii;
    vector <point>::iterator jj;
    for (ii = po.begin(); ii != po.end(); ii++)
    {
        for (jj = po.begin(); jj != po.end(); jj++)
        {
            cout << distance(ii,jj) << " ";
        }
    }
    return 0;
}


So here we have successful compilation, it doesn't crash - just a sense of wondering why it doesn't work as intended.
Last edited on
Great example, TheIdeasMan!

from now on, whenever I send this ...
http://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice

... I'll also try and remember to include this ...
http://www.cplusplus.com/forum/general/214265/2/#msg998774



@The IdeasMan,
what does it prove ?
If I remove the using namespace std and add std:: I get the same results.
In both cases the compiler does not call float distance(point *p1, point *p2) but uses the std version

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <vector>
#include <cmath>
#include <iostream>

// using namespace std;

typedef struct point
{
  float x;
  float y;
} point;

float distance(point *p1, point *p2)
{
  std::cout << __FUNCSIG__ << "\n";
  return sqrt((p1->x - p2->x)*(p1->x - p2->x) +
    (p1->y - p2->y)*(p1->y - p2->y));
}

int main()
{
  std::vector <point> po;
  point p1; p1.x = 0; p1.y = 0;
  point p2; p2.x = 1; p2.y = 1;
  po.push_back(p1);
  po.push_back(p2);

  std::vector <point>::iterator ii;
  std::vector <point>::iterator jj;
  for (ii = po.begin(); ii != po.end(); ii++)
  {
    for (jj = po.begin(); jj != po.end(); jj++)
    {
      std::cout << std::distance(ii, jj) << " ";
    }
  }
  system("pause");
  return 0;
}
> what does it prove ?

It doesn't prove anything.

If the intent was to call float distance(point *p1, point *p2), it is a technical blunder any way.
There is no requirement that an implementation must provide for an implicit conversion from the iterator of a vector to a pointer; and most implementation don't.
http://coliru.stacked-crooked.com/a/ef07bbc83c28f14b
http://rextester.com/WITNG48099

As an aside, with or without the using namespace std ;, (if the header <iterator> was directly or indirectly included) the function that would be called for the unqualified distance(ii,jj) is std::distance(). To understand why, see: http://en.cppreference.com/w/cpp/language/adl
Last edited on
@gunnerfunner

The example I posted was one of the two examples in the same link that you posted :+)

@JLBorges

With the greatest respect, whether that example was a technical blunder or not, the point was: that person's intention was to have their own distance function, and they were surprised to find out the rather different std::distance was being called, and there was no compilation error or warning. They didn't find out until they asked the question.

@everyone
I think it was Cubbi who once said that: std::copy specifies that one wants the std version, not boost::copy, or some other copy from somewhere.

As Thomas1965 alluded to, it is a good idea to put one's own stuff into it's own namespace - then you get a compilation error: in this case the technical blunder JLBorges mentioned.

1
2
3
namespace me {
float distance(point *p1, point *p2)
{


std::cout << me::distance(ii, jj) << " ";

In function 'int main()':
36:39: error: cannot convert 'std::vector<point>::iterator {aka __gnu_cxx::__normal_iterator<point*, std::vector<point> >}' to 'point*' for argument '1' to 'float me::distance(point*, point*)'


So this is what we want, a compiler error :+)

Some people put things like: using std::cout; That is fine, but it gets tiresome: it's easy to accumulate 20 of those, especially if using algorithms.

Finally, it is too hard to remember or otherwise keep track of what identifiers are being used in the STL, so just avoid that altogether by putting std::

We could all argue this all day, but in the end having std:: before each std thing is the best practise, and that is why experts and many others do exactly that, all the time :+) And my intention of bringing this up in the first place was to encourage good practise, even if it was my 2 cents worth.
Last edited on
> the point was: that person's intention was to have their own distance function, and they were
> surprised to find out the rather different std::distance was being called, and there was no
> compilation error or warning. They didn't find out until they asked the question.

My point is: the presence or absence of the directive using namespace std; is irrelevant to that example.

Because of ADL, the behaviour of the program would be identical with or without a using namespace std;
in either case, the call to unqualified distance would result in:
::distance being called if the type of std::vector<point>::iterator happens to be point*,
std::distance being called otherwise.
I think the simple question is, as a C++ practitioner do you (meaning each one of us here, not any particular person) include using namespace std; in your own programs or not? If not, there is no reason to create arguments in favor of its inclusion (or at least not against it). If yes, then by all means continue to do so if you think that's OK for you but let others do what they deem best. for myself the argument is quite overwhelming not to include namespace std;

ps: i recall some months back there was a similar discussion on using underscores in variable names where various solutions were being peddled that might be acceptable by the standard but hardly ever done until upon challenge the lead protagonist (?) on that thread admitted s/he never did what s/he was seemingly advocating in his/her own programs
@JLBorges

Yes, I understood your point. It was perhaps a bad example, but the underlying idea of not having using namespace std; was the main thing.

Regards :+)
> Yes, I understood your point.

That is what I wanted to point out; I'm glad.

It is not possible to write readable C++ code (which uses the standard library facilities) if we insist that, without exception, every name looked up in the namespace std must be a name qualified with std::

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <vector>
#include <string>
#include <iterator>
#include <numeric>
#include <iomanip>

int main()
{
    const std::vector< std::string > seq { "abc", "de", "fghi", "jklmn", "opq", "rstuv", "wxyz" } ;
    const std::string cat = "result: " ;

    // (1) fine: ADL all through (all names except std::cout are unqualified)
    std::cout << quoted( accumulate( begin(seq), end(seq), cat ) ) << '\n' ;

    // (2) also fine: ADL only for operator<< 
    // (all other names to be looked up in namespace std are qualified with std::)
    std::cout << std::quoted( std::accumulate( std::begin(seq), std::end(seq), cat ) ) << '\n' ;

    // (3) utterly terrible: not using ADL at all 
    // (every name to be looked up in namespace std is qualified with std::)
    std::operator<< ( std::cout, std::quoted< char, std::char_traits<char>, std::allocator<char> >( std::accumulate( std::begin(seq), std::end(seq), cat ) ) ) << '\n' ;
}

http://coliru.stacked-crooked.com/a/9b9624b729a73309
http://rextester.com/XMCO27545
@JLBorges

Well we have given this particular topic a good thrashing, hopefully educational for all :+)

I agree, Example 3 is taking things to extremes, qualifying operators and all template arguments is too much :+) When I said "put std:: before each std thing", I wouldn't have expected any beginner to even know about template parameters and operators to that extent.

Having seen all the code you have posted since you joined, it seems that the vast majority of it is in the format of example 2.

Another motivation for me mentioning not having using namespace std; is to point people in the general direction of writing code like you do :+)

With the ADL, I wonder whether in the future it could be taken even further: could there be defaulted begin and end iterators? As in:

std::cout << quoted( accumulate( seq, cat ) ) << '\n' ;

There are a lot of STL functions that require begin and end iterators as arguments, if the above is possible - things could be much simpler. On the other hand there is ranged based for, which seems to be able to deduce begin and end. I understand the flexibility that comes from being able to specify various iterators (const, reverse etc., and for partial sequences), but could this be an additional overload ?

Perhaps something like this (I started with the implementation shown on cppreference). I tested it, it seemed to work like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <iterator>
#include <vector>
#include <iomanip>

namespace Test {
  template<class S, class T>

  // similar to std::accumulate, but begin and end iterators are implied
  T accumulate(S seq, T init)
  {
    auto first = std::begin(seq);
    auto last = std::end(seq);

    for (; first != last; ++first) {
        init = init + *first;
      }
    return init;
  }
} // end namespace Test

int main(   )
{
  const std::vector< std::string > seq { "abc", "de", "fghi", "jklmn", "opq", "rstuv", "wxyz" } ;
      const std::string cat = "result: " ;

    std::cout << std::quoted( Test::accumulate(seq,cat) ) << '\n' ;


  return 0;
}


Regards :+)
Last edited on
> Having seen all the code you have posted since you joined,
> it seems that the vast majority of it is in the format of example 2.

Yes, that is the style that I favour, and use most of the time
(until it starts getting needlessly verbose and impairs readability).

However, as far as implementation files are concerned, I realise that this is mainly a matter of style and personal preference. I accept that these are valid view points:

In short: You can and should use namespace using declarations and directives liberally in your implementation files after #include directives and feel good about it. Despite repeated assertions to the contrary, namespace using declarations and directives are not evil and they do not defeat the purpose of namespaces. Rather, they are what make namespaces usable.
...
But using declarations and directives are for your coding convenience, and you shouldn't use them in a way that affects someone else's code. In particular, don't write them anywhere they could be followed by someone else's code: Specifically, don't write them in header files (which are meant to be included in an unbounded number of implementation files, and you shouldn't mess with the meaning of that other code) or before an #include (you really don't want to mess with the meaning of code in someone else's header).

- Sutter and Alexandrescu in 'C++ Coding Standards: 101 Rules, Guidelines, and Best Practices'


SF.6: Use using namespace directives ... for foundation libraries (such as std) ...

using namespace can lead to name clashes, so it should be used sparingly. However, it is not always possible to qualify every name from a namespace in user code (e.g., during transition) and sometimes a namespace is so fundamental and prevalent in a code base, that consistent qualification would be verbose and distracting.

CoreGuideLines https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rs-using



> There are a lot of STL functions that require begin and end iterators as arguments,
> if the above is possible - things could be much simpler.

Boost already has a Range library.
http://www.boost.org/doc/libs/1_64_0/libs/range/doc/html/index.html

The Ranges TS is currently at the PDTS stage:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4651.pdf

From an early paper that elaborates on the motivation for addition of ranges to C++:
A range is an object that refers to a sequence of elements, conceptually similar to a pair of iterators. One prime motivation for ranges is to give users a simpler syntax for calling algorithms. Rather than this:
1
2
std::vector<int> v { /*...*/ };
std::sort( v.begin(), v.end() );

Ranges would give us a pithier syntax: std::sort( v );

Allowing algorithms to take a single range object instead of separate begin and end iterators brings other benefits besides convenience. In particular:

It eliminates the possibility of mismatched iterators.
It opens the door to range adaptors which lazily transform or filter their underlying sequence in interesting ways.
Range adaptors are far more compelling than iterator adaptors due to the fact that only a single object, the range object, needs to be adapted; hence, adaptors can be easily chained to create lazy computational pipelines, as in the code below which sums the first 10 squares:
1
2
3
int total = accumulate(view::iota(1) |
                       view::transform([](int x){return x*x;}) |
                       view::take(10), 0);


...

From the perspective of the standard library, a range is a pair of iterators. But there are other interesting ways to denote a range of elements:
An iterator and a count of elements
An iterator and a (possibly statefull) predicate that indicates when the range is exhausted.

One of these three range types can be used to denote all other range types, like an iterator and a sentinel value (e.g. a null-terminated string), or a range that spans disjoint ranges. Ideally, we would like our Range abstraction to be general enough to accommodate the three different kinds of ranges since that would increase the applicability of the algorithms.

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4128.html#motivation-and-scope
Last edited on
@JLBorges

Thanks for your always awesome answers :+D
Topic archived. No new replies allowed.
Pages: 12