What Is the Logic Behind the "Using" Keyword in C++

What is the logic behind the using keyword in C++?

In C++11, the using keyword when used for type alias is identical to typedef.

7.1.3.2

A typedef-name can also be introduced by an alias-declaration. The
identifier following the using keyword becomes a typedef-name and the
optional attribute-specifier-seq following the identifier appertains
to that typedef-name. It has the same semantics as if it were
introduced by the typedef specifier. In particular, it does not define
a new type and it shall not appear in the type-id.

Bjarne Stroustrup provides a practical example:

typedef void (*PFD)(double);    // C style typedef to make `PFD` a pointer to a function returning void and accepting double
using PF = void (*)(double); // `using`-based equivalent of the typedef above
using P = [](double)->void; // using plus suffix return type, syntax error
using P = auto(double)->void // Fixed thanks to DyP

Pre-C++11, the using keyword can bring member functions into scope. In C++11, you can now do this for constructors (another Bjarne Stroustrup example):

class Derived : public Base { 
public:
using Base::f; // lift Base's f into Derived's scope -- works in C++98
void f(char); // provide a new f
void f(int); // prefer this f to Base::f(int)

using Base::Base; // lift Base constructors Derived's scope -- C++11 only
Derived(char); // provide a new constructor
Derived(int); // prefer this constructor to Base::Base(int)
// ...
};

Ben Voight provides a pretty good reason behind the rationale of not introducing a new keyword or new syntax. The standard wants to avoid breaking old code as much as possible. This is why in proposal documents you will see sections like Impact on the Standard, Design decisions, and how they might affect older code. There are situations when a proposal seems like a really good idea but might not have traction because it would be too difficult to implement, too confusing, or would contradict old code.


Here is an old paper from 2003 n1449. The rationale seems to be related to templates. Warning: there may be typos due to copying over from PDF.

First let’s consider a toy example:

template <typename T>
class MyAlloc {/*...*/};

template <typename T, class A>
class MyVector {/*...*/};

template <typename T>

struct Vec {
typedef MyVector<T, MyAlloc<T> > type;
};
Vec<int>::type p; // sample usage

The fundamental problem with this idiom, and the main motivating fact
for this proposal, is that the idiom causes the template parameters to
appear in non-deducible context. That is, it will not be possible to
call the function foo below without explicitly specifying template
arguments.

template <typename T> void foo (Vec<T>::type&);

So, the syntax is somewhat ugly. We would rather avoid the nested ::type
We’d prefer something like the following:

template <typename T>
using Vec = MyVector<T, MyAlloc<T> >; //defined in section 2 below
Vec<int> p; // sample usage

Note that we specifically avoid the term “typedef template” and
introduce the new syntax involving the pair “using” and “=” to help avoid
confusion: we are not defining any types here, we are introducing a
synonym (i.e. alias) for an abstraction of a type-id (i.e. type
expression) involving template parameters. If the template parameters
are used in deducible contexts in the type expression then whenever
the template alias is used to form a template-id, the values of the
corresponding template parameters can be deduced – more on this will
follow. In any case, it is now possible to write generic functions
which operate on Vec<T> in deducible context, and the syntax is
improved as well. For example we could rewrite foo as:

template <typename T> void foo (Vec<T>&);

We underscore here that one of the primary reasons for proposing
template aliases was so that argument deduction and the call to foo(p)
will succeed.


The follow-up paper n1489 explains why using instead of using typedef:

It has been suggested to (re)use the keyword typedef — as done in the
paper [4] — to introduce template aliases:

template<class T> 
typedef std::vector<T, MyAllocator<T> > Vec;

That notation has the advantage of using a keyword already known to
introduce a type alias. However, it also displays several
disavantages among which the confusion of using a keyword known to
introduce an alias for a type-name in a context where the alias does
not designate a type, but a template; Vec is not an alias for a
type, and should not be taken for a typedef-name. The name Vec is a
name for the family std::vector< [bullet] , MyAllocator< [bullet] > >
– where the bullet is a placeholder for a type-name. Consequently we
do not propose the “typedef” syntax. On the other hand the sentence

template<class T>
using Vec = std::vector<T, MyAllocator<T> >;

can be read/interpreted as: from now on, I’ll be using Vec<T> as a
synonym for std::vector<T, MyAllocator<T> >. With that reading, the
new syntax for aliasing seems reasonably logical.

I think the important distinction is made here, aliases instead of types. Another quote from the same document:

An alias-declaration is a declaration, and not a definition. An alias-
declaration introduces a name into a declarative region as an alias
for the type designated by the right-hand-side of the declaration. The
core of this proposal concerns itself with type name aliases, but the
notation can obviously be generalized to provide alternate spellings
of namespace-aliasing or naming set of overloaded functions (see ✁
2.3 for further discussion). [My note: That section discusses what that syntax can look like and reasons why it isn't part of the proposal.] It may be noted that the grammar production alias-declaration is acceptable anywhere a typedef
declaration or a namespace-alias-definition is acceptable.

Summary, for the role of using:

  • template aliases (or template typedefs, the former is preferred namewise)
  • namespace aliases (i.e., namespace PO = boost::program_options and using PO = ... equivalent)
  • the document says A typedef declaration can be viewed as a special case of non-template alias-declaration. It's an aesthetic change, and is considered identical in this case.
  • bringing something into scope (for example, namespace std into the global scope), member functions, inheriting constructors

It cannot be used for:

int i;
using r = i; // compile-error

Instead do:

using r = decltype(i);

Naming a set of overloads.

// bring cos into scope
using std::cos;

// invalid syntax
using std::cos(double);

// not allowed, instead use Bjarne Stroustrup function pointer alias example
using test = std::cos(double);

using keyword in C++

The using keyword is used to define type aliases. The reasons your professor is using it are:

  • readability
  • being more descriptive
  • avoid unnecessary typename

Readability and descriptiveness

You can use type aliases to semantically (and only that) restrict a specific type, making the name more descriptive for the specific use.

An example is:

using fileName = std::string;

The fileName alias is used to describe a file name string, not just any string. This makes for readable function signatures too.

I feel like I have to iterate this again: it's simply an alias. Any function taking fileName as an argument will work just fine with any std::string argument.

Unnecessary typenames

Some may seem unnecessary, like:

using setOfPaths = std::set<filePath>;

but in some cases they can be actually used to avoid having to specify typename in situations like:

template<typename Type>
struct something {
using something_iter = typename std::set<Type>::iterator;
};

with:

template<typename Container>
using itertype = typename Container::iterator;

template<typename Type>
struct something {
using something_iter = itertype<std::set<Type>>;
};

By moving typename in a specific alias we can reuse itertype in multiple other occasions effectively avoiding typename.

A note on typedef

There's another way to define type aliases: typedef. That keyword is inherited from C and does not allow for templated aliases, like:

template<typename Type>
using vec = std::vector<Type>;

A note on type safety

This is not actually any more type safe than not using aliases at all. Again, fileName and std::string are exactly the same type. You can use both interchangeably.

A possible next step would be to define a specific fileName class/struct type with its own specific invariants.

What are the uses of using in C#?

The reason for the using statement is to ensure that the object is disposed as soon as it goes out of scope, and it doesn't require explicit code to ensure that this happens.

As in Understanding the 'using' statement in C# (codeproject) and Using objects that implement IDisposable (microsoft), the C# compiler converts

using (MyResource myRes = new MyResource())
{
myRes.DoSomething();
}

to

{ // Limits scope of myRes
MyResource myRes= new MyResource();
try
{
myRes.DoSomething();
}
finally
{
// Check for a null resource.
if (myRes != null)
// Call the object's Dispose method.
((IDisposable)myRes).Dispose();
}
}

C# 8 introduces a new syntax, named "using declarations":

A using declaration is a variable declaration preceded by the using keyword. It tells the compiler that the variable being declared should be disposed at the end of the enclosing scope.

So the equivalent code of above would be:

using var myRes = new MyResource();
myRes.DoSomething();

And when control leaves the containing scope (usually a method, but it can also be a code block), myRes will be disposed.

How to use using keyword in C++

In a header file... the following example is evil. Never use using namespace... in the global scope of a header file. It forces a lot of unasked for symbols on the user that can cause very hard to fix problems if they clash with other headers.

#include <memory>
using my_namespace1::component1;
using my_namespace2::component2;
namespace my_application {
namespace platform_logs {
class backtrace_log {
//code that creates instances of my_namespace1::component1 and my_namespace2::component2
};
}
}

On the other hand this next example is fine, but to be used with caution. It only makes sense if you want to include all those symbols in your API. This is often the case with internal project name spaces but less likely with third party namespaces.

I would especially avoid even this with very large namespaces like std::.

#include <memory>    
namespace my_application {
namespace platform_logs {
using my_namespace1::component1;
using my_namespace2::component2;

class backtrace_log {
//code that creates instances of my_namespace1::component1 and my_namespace2::component2
};
}
}

Use cases of keyword using in C++11

Simply put, when the base class depends on a template parameter, its scope is not inspected to resolve names. Hence, you cannot refer to noise_ in Derived using just noise_. You should either write this->noise_, or introduce the name with using.

Is it wise to use the `this` keyword in C?

Using this in any fashion you want is totally valid C.

What you have to ask yourself, by the way these apply to any C++ reserved words like class, final etc, is :

  • Do I use a program that highlights this as a keyword conveing the wrong message ? e.g. Visual Studio highlights this even when you're in a .c file so some confusion may arise.
  • Do I plan to promote my code to C++ in the future ? In such a case you'll have some extra work to do that could be avoided.
  • Does my code interact with C++ ? This is not a problem per se but you have to bear in mind that your code will interact with C++ programmers as well. And you don't won't to confuse people that may not be aware of C in great detail (even though someone may say it's their duty do be aware of what they're doing when reading another language).

Since this is something that can be avoided I find using it immoral but not incorrect.

I'm not saying you have to study C++ prior to writing C, but once you know something, it's a good practice to make good use of it.

A subtle problem you may cause is to make your code 'uncallable' from C++ for example a

#define this some_definition

in a C header file that is later included from C++ may have weird effects to your code.

using' keyword before local variable declaration in C#?

It is a C# 8 syntax sugar for a traditional using statement which ensures that Dispose() method will be called for a type implementing IDisposable interface.

See https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement#example

Is it possible to define keywords in C

how do you define a keyword in C?

You don't. It's impossible.

What you can do is to use macros. They are basically just advanced text replacement. The preprocessor is run before the compiler. That is, in principal. On modern compilers they are run at the same time, but the behavior is the same.

If you want to look at the source code after the preprocessor, you can use the -E parameter to the compiler.

Here is an example of how you can make C code more like Pascal. DON'T DO THIS! JUST FOR FUN!

#include <stdio.h>

#define Begin {
#define End ;}
#define Writeln(X) puts(X)

int main(void)
Begin
Writeln("Hello, World!");
Writeln("Hello again")
End


Related Topics



Leave a reply



Submit