For my project I am using some pretty convoluted data structures, e.g.
std::unordered_map<int, std::list<std::shared_ptr<const Foo>>>
for which I would like to declare type aliases for readability. The code on which I built my project on already did this by putting using
statements globally in the header files:
// bar.h
#ifndef BAR_H
#define BAR_H
#include <unordered_map>
#include <list>
#include <memory>
#include "foo.h"
using FooTable = std::unordered_map<int, std::list<std::shared_ptr<const Foo>>>;
class Bar {
FooTable create_foo();
};
#endif
Since my C++ knowledge was a little rusty, I just adopted this style -- but now I read that using using
in that way can be problematic, since it forces this alias on everything that includes this header.
Despite a good amount of googling, I could not find a concrete answer on how to handle this properly, only lots of statements on what not to do. So, I just put the using inside the class:
// bar.h
#ifndef BAR_H
#define BAR_H
#include <unordered_map>
#include <list>
#include <memory>
#include "foo.h"
class Bar {
using FooTable = std::unordered_map<int, std::list<std::shared_ptr<const Foo>>>;
FooTable create_foo();
};
#endif
However this has the drawback, that I need to restate the alias in the source file:
// bar.cpp
#include "bar.h"
using FooTable = std::unordered_map<int, std::list<std::shared_ptr<const Foo>>>;
FooTable Bar::create_foo()
{
...
}
While this seems to work, I am not sure whether this is safe... and my gut tells me it is kind of ugly. So before I rewrite my whole project like this I thought I'd ask: Is a there a better/more elegant/safer way to do this? Or should I just refrain from using type aliases in header files completely?
However this has the drawback, that I need to restate the alias in the source file:
That is incorrect. You need only make it public
then specify the proper scope, so you'd call it Bar::FooTable
outside of the scope of Bar
(which includes return types, unless trailing!):
Bar::FooTable Bar::create_foo()
{ /* ... */ }
or
auto Bar::create_foo() -> FooTable
{ /* ... */ }
(Just FooTable
is fine within the definition, as it's a member!)
Your approach is fine, though I'd put everything in a namespace too. Then it doesn't really matter whether your alias is in the class or not: it's still self-contained within your own code. It becomes purely a matter of style, with little to no impact on anyone else.