Using Declarations, Using Directive, or Full Scope Resolution.

closed account (z05DSL3A)
using Declarations, ie:
1
2
3
using std::cout;
using std::cin;
using std::end;


add names to the scope in which they are declared. The effect of this is:
» a compilation error occurs if the same name is declared elsewhere in the same scope;
» if the same name is declared in an enclosing scope, the the name in the namespace hides it.

The using directive, ie using namespace std;, does not add a name to the current scope, it only makes the names accesable from it. This means that:
» If a name is declared within a local scope it hides the name from the namespace;
» a name in a namespace hides the same name from an enclosing scope;
» a compilation error occurs if the same name is made visible from multiple namespaces or a name is made visible that hides a name in the global name space.

So, I have always gone with the advice of... prefer Using Declarations to Using Directive but prefer full scope resolution to Using Declarations.

However, recently I read something that suggested that using directives in the function definitions is a better way to go* as it doesn't hamstring the optimiser when it comes to template specializations.**

Has anyone read this or something similar (or feel free to have a discussion about it)?

_____________________________________________________
* it was something like that...trying to remember where I read it.
** realy, totaly trying to remember what I read here.
closed account (E0p9LyTq)
I personally prefer to use neither using declarations or using directives. Using either is lazy to me. Save a couple of keystrokes to potentially add in unneeded problems with scoping.

Let the religious wars begin. I'm outta here.
The using directive, ie using namespace std;, does not add a name to the current scope, it only makes the names accessible from it.

A using directive makes names visible within a scope from the least common ancestor of the using directive itself and the "used namespace" in the namespace hierarchy.

» a compilation error occurs if the same name is made visible from multiple namespaces or a name is made visible that hides a name in the global name space.

Just making the same name visible isn't a problem by itself. There's an error if lookup + overload resolution (if applicable) fails to identify exactly one entity.

However, recently I read something that suggested that using directives in the function definitions is a better way to go* as it doesn't hamstring the optimiser when it comes to template specializations.


Unless using directives are allowed to modify the program's semantics, I don't see why they should interact with the compiler optimizer. I can't claim it does nothing, but I'd be interested to learn why and how (and if) there is any interaction.
Like all scope resolution issues, it is complex...

But normal. If you using std::something and you already have another something, they only clash when the compiler cannot figure out which something you intend.

The using declaration is very useful for providing overloaded capabilities. I personally prefer to keep them to a local scope, but they are useful.

For example, suppose I wish to do something to any valid container:

1
2
3
4
5
6
7
8
template <typename ContainerType>
void something_awesome( ContainerType& container )
{
  using std::begin;
  using std::end;
  std::sort( begin( container ), end( container ) );
  ...
}

This provides the ability to use namespace-dependent lookup to find the correct begin and end functions for the container, no matter how my container is defined — as long as there is an acceptable pair of functions to begin and end, I’m good.

1
2
3
4
5
int main()
{
  int primes[] = { 7, 2, 11, 3, 5, 17, 13 };
  something_awesome( primes );  // It works!
}

Hope this helps.
closed account (z05DSL3A)
Okay I remembered where I read it, Discovering Modern C++: An Intensive Course for Scientists, Engineers, and Programmers, it is to do with Argument-Dependent Lookup.

1
2
3
4
5
6
7
template <typename T, typename U>
inline void some_function(T& x, T& y, const U& z, int i)
{
    ...
    std::swap(x, y); // can be expensive
    ...
}

vs
1
2
3
4
5
6
7
8
template <typename T, typename U>
inline void some_function(T& x, T& y, const U& z, int i)
{
    using std::swap;
    ...
    swap(x, y); // involves ADL
    ...
}

There is a bit for me to reread but I can see why it was ticking over a the back of my head. :0)

Last edited on
Dang, yes, I meant to say argument-dependent lookup. Too bad I can't remember what things are called for the life of me.

https://www.youtube.com/watch?v=o2dtpnp8Jgo
> can be expensive

Here is a toy example to illustrate why it could be expensive:
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>
#include <cstdlib>

namespace A
{
    struct B // swappable
    {
        B() = default ;
        B( const B& ) = default ;
        B( B&& ) noexcept { std::cout << "somewhat expensive move construction\n" ; }
        B& operator= ( const B& ) = default ;
        B& operator= ( B&& ) noexcept
        {
            std::cout << "somewhat expensive move assignment\n" ;
            return *this ;
        }
        ~B() { std::cout << "somewhat expensive destruction\n" ; }

        void swap( B& ) { std::cout << "specially optimised swap\n" ; }
    };

    // make B swappable by providing a non-member swap swap
    // in the same namespace as B
    void swap( B& first, B& second ) { first.swap(second) ; }
}

template < typename T >
inline void wrong_swap( T& x, T& y )
{
    // ...
    std::swap(x, y); // can be expensive (theoretically, can fail)
    // ...
}

template < typename T >
inline void right_swap( T& x, T& y )
{
    // ...
    using std::swap ;
    swap(x, y); //
    // ...
}

int main()
{
    A::B b1, b2 ;

    std::cout << "wrong swap\n-----------\n" ;
    wrong_swap( b1, b2 ) ;
    // somewhat expensive move construction
    // somewhat expensive move assignment
    // somewhat expensive move assignment
    // somewhat expensive destruction

    std::cout << "\nright swap\n-----------\n" ;
    right_swap( b1, b2 ) ; // specially optimised swap

    std::exit(0) ; // to elide destruction of first and second (suppress noise)
}

http://coliru.stacked-crooked.com/a/fce71f2095b5bb91

Many standard library functions (for example, many algorithms) expect their arguments to satisfy Swappable, which means that any time the standard library performs a swap,
it uses the equivalent of using std::swap; swap(t, u);.

Typical implementations either

1) Define a non-member swap in the enclosing namespace, which may forward to a member swap if access to non-public data members is required
2) Define a friend function in-class (this approach hides the class-specific swap from name lookup other than ADL)
https://en.cppreference.com/w/cpp/named_req/Swappable
Last edited on
Darn, I was going to suggest the using std::swap technique when I first read this, because I knew you weren't just asking about the [dis-]advantages of certain scoping practices, but it sounded like you were looking for an end-result that used a 'using directive' and not a 'using declaration'. Ah well, glad you remembered it!

A bit off-topic, but this usage of 'using' in C++ is one of things I find to be the most at odds with languages like C# and Java. In C#, using declarations are much, much better than not using it. You'll rarely find any source file that doesn't have a few using declarations at the top. It isn't lazy. It makes refactoring code so much nicer, because often you just need to change one using declaration at the top of the file as opposed to 15x actual variables/function calls.

Never really had the equivalent problem/solution in C++ though... probably because the standard library is mostly all just under std::, as opposed to System.IO.File, etc., and C++ compiler errors (especially with templates) are much worse than C# compiler errors, which will very clearly just say there's an ambiguity. Not to mention the whole #include syntax throws a wrench at everything.

Cool example, JLBorges!
Last edited on
closed account (z05DSL3A)
Ganado wrote:
...but it sounded like you were looking for an end-result that used a 'using directive' and not a 'using declaration'

nuts I was thinking declaration, didn't even realise I had written directives.

-----===##===-----

Thanks everyone.
Topic archived. No new replies allowed.