7

I have this little class widget that uses a std::string. It uses it in many places, often in conjunction to a std::vector. So you can see, that the typenames become very long and annoying.

I want to utilize the using keyword, i.e. using std::string;

The question is, where is the best place to place it?

// widget.h file
#ifndef WIDGET
#define WIDGET

// (1)
namespace example {
    // (2)

    namespace nested {
        // (3)

        class widget {  
        public:
            // (4)
            ...
        private:
            // (5)
            std::string name_;
            ...
        };

    }
}

#endif

My questions are:

  1. If I place it in (1) then everybody who includes widget.h will have their scope polluted with string?
  2. In places (2) and (3), it's the same story as in 1. only that the namespaces example and example::nested will be polluted in a second file that includes widget.h?
  3. In places (4) and (5), the declaration is quite isolated, but will it be visible in the implementation (Cpp) file and in inheriting classes?

Thanks in advance!

Xlaudius
  • 1,757
  • 2
  • 13
  • 16
  • I think it depends on what you exactly want. I guess the best place to put it is where you only need to use it. If you only want to use it within the class, then 4 and 5 would be reasonable. – Kakalokia Mar 07 '13 at 16:19
  • Whilst position 4 & 5 seem like the perfect choice, I can't get g++ to accept that - I get `using-declaration for non-member at class scope`. – Mats Petersson Mar 07 '13 at 16:33
  • but `using base_class::shadowed_function` works ? – Xlaudius Mar 07 '13 at 17:27

1 Answers1

13

Do not do it in (1).
Everybody will curse your name for a thousand years.
As a user of your class I don't mind you polluting your own namespace. But I will be upset if you pollute any of my namespaces (including global) as this will affect how my code is compiled. Why is "using namespace std" considered bad practice?

You can't use it at (4) or (5).

Since I (personally) would want to bind it as close as possible to the point of usage (to prevent pollution).
The best you can do is (3).

But I would not even do that. I am explicit about anything from standard. But I would typedef my container type.

private: //(so at 5) Don't need to expose internal details of your class.
    typedef std::vector<std::string>   MyCont;

This is a better technique as you will only need to make a change in one place and changes will cascade.

// Sub typedefs now will no longer need to change if you change
// The type of container. Just change the container typedef and
// now the iterators are automatically correct.
public: //(so at 4)  Iterators are public (and not exposing the implementation).
    typedef MyCont::iterator       iterator;
    typedef MyCont::const_iterator const_iterator;
Community
  • 1
  • 1
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • 3
    Note that C++11 alias syntax is available too `using MyCont = std::vector;` – Matthieu M. Mar 07 '13 at 16:37
  • @MatthieuM.: Interesting I though that only applied to namespaces. – Martin York Mar 07 '13 at 16:38
  • 1
    It used to only apply to namespaces in C++03, but in C++11 the alias syntax was extended (you probably saw the `template using MyVector = std::vector>;` examples). – Matthieu M. Mar 07 '13 at 16:40
  • @MatthieuM.: My C++11 is not up-to speed. I am still very much a C++03 person that is learning C++11 slowly. Now that you show the template version I seem to remember the discussions (but not having used C++11 on real projects most of these things will not stick until I use them for real (a couple of times)). – Martin York Mar 07 '13 at 16:44
  • @MatthieuM.: Would you use `using MyCont = std::vector;` over `typedef std::vector MyCont;`? – Martin York Mar 07 '13 at 16:46
  • I would, but that's certainly subjective. I prefer it because when the types to be `typedef` are very long, then it becomes difficult what the "type to use" is; whereas with `using X =` we have a natural assignment syntax with the new name always sitting at the same place on the line. And there is the argument of consistency with template aliases. But since the functionality is otherwise strictly equivalent, it certainly is a subjective choice. – Matthieu M. Mar 07 '13 at 17:02
  • Thanks for the answer! I have one last question. If I have two files, one containing `a::b::class_1` and the second `a::b::class_2` (where `a::b` is just a nested namespace) and in the first file I use `using std::string` in place `(3)` and if the 2nd file includes the 1st, then will `string` be visible without the `std::` prefix? – Xlaudius Mar 07 '13 at 18:50
  • 1
    @Xlaudius: Yes. But the problem there is if you include the second file without including the first things stop to compile. You have introduced a coupling between the files were to use the second one you must include the first one. That is not a good idea. To be blunt the extra 5 characters should not be a burden. – Martin York Mar 07 '13 at 19:05