Your last example is very much readable, but it depends on where you define the typedef. Local scope typedefs (like in your second example) are IMVHO almost always a win.
I still like your third example best, but you might want to think about the nameing, and give the iterators names which tell the intend of the container.
Another option would be to make a template out of your function, so that it works with different containers, too. Along the lines of
template <typename Input_iterator> ... sum(Input_iterator first, Input_iterator last)
which is also very much in the spirit of the STL.
In C++, the inline
specifier does not affect whether a compiler will inline a function call. It has effects that make inlining possible, but that is not the main purpose. If you have a private helper function that you want to be inlined, instead ensure that it has internal linkage – e.g. by putting it in an anonymous namespace (C++11). A declaration with internal linkage can only be accessed from within the current compilation unit.
An inline
function may have multiple definitions. This is important when you define a function inside a header file. Usually, you declare functions in a header and implement it in a .cpp file. Other compilation units include the declaration in the header and are later linked with the definition. But if the function is defined in a header, the same function now exists in multiple compilation units. When they are linked, the linker sees these multiple definitions for your function. Which is the correct definition? The linker will raise an error.
With an inline
specifier, you tell the linker that these multiple definitions are OK, and they all refer to the same function. Additionally, the definition of an inline
function must be present in the same compilation unit.
Some functions are implicitly inline – in particular, any methods and functions within a class declaration:
class Foo {
public:
void method() { /* implicitly inline */ }
static void static_method() { /* implicitly inline */ }
friend void friend_function() { /* implicitly inline */ }
};
void free_function() { /* not implicitly inline */ }
Don't declare a function as inline because it is short. Declare it as inline because you've defined it in a header.
Further reading: inline
specifier on cppreference.com
The Google style guide you cite does not discuss when the inline
keyword should be used, but whether functions should be implemented inline (i.e. in the header file). For simple functions like getters in a class this is usually perfectly fine. For larger, more complicated functions, it is usually better to implement them separately (though this is not possible for templates).
Best Answer
I typically use one of the two ways.
typedef
at the place-of-first-declaration.typedef
at each place-of-use, and make it only visible to that place-of-use (by putting it inside the class or method that uses it).(1) Put the typedef close to the type that is being wrapped.
(2) Make the typedef visible only to each class that uses it.
Most of the time, the template relevant to me is either
std::unique_ptr
andstd::shared_ptr
. Furthermore, I will just decide that a class will either use one way or the other, and then typedef that smart pointer wrapper as "MyClassOnePtr". Draconian, but a library's main author is supposed to know what is the best for the library most of the time.If it is not obvious which one of the two smart pointers should be preferred, then I will not put the typedef in the first header (so, I won't use option #1 unless the choice is obvious.)
Most of the time, you will realize that option #2 does not always shield the use of
Optional<T>
from the end-user. That is, the application logic may require users ofMyClassX
to deal withOptional<T>
when interacting with it. When that happens, you can't hide it anymore. It is not an implementation detail; it is part of the visible surface.Finally, you should be aware of the C++ limitation to forward-declare things. Namely, there are times where C++ needs to know up-front:
See this question on Stackoverflow (about
unique::ptr
) for examples of such limitations.Another unrelated thing I would like to share, after reading ixrec's answer.
I started following a "nothing in the default namespace" policy after finding that you can't get Doxygen (a widely used C++ documentation to HTML generator) to generate well-organized documentation unless you categorize your classes by using namespaces. It seems it doesn't matter how you name those namespaces; as long as Doxygen sees them as distinct, and human users don't complain about it, any namespacing approach will be fine.