Static, nonmember or static nonmember function?

前端 未结 3 599
轮回少年
轮回少年 2021-02-06 00:30

Every time I have some functionality which is in the direction of \"utility\", I end up wondering which option is the best. For instance, printing message structs (own or extern

相关标签:
3条回答
  • 2021-02-06 01:12

    Don't use classes as namespaces. Using a free (ie. nonmember) function inside a namespace is the simplest thing.

    Moreover, the function shouldn't be static if it has to be used across multiple translation units. Otherwise, it will be duplicated.

    Using classes as namespace is stupid: why make a class which you won't instantiate ?

    If some state is to be kept, then have a global state somewhere: static variable inside the function, utility global object (possibly in a "private" namespace, or as a static global variable in one of your translation units). Don't write classes you don't instantiate.

    Alas, people with a C#/Java background are used to do this stupid thing, but it is because their language designers have decided unilaterally that free functions are evil. Whether they should be shot or not is a matter of religion.

    As a last word of caution: global state should be rarely used. Indeed, it couples your code to the existence of the global state in a way you don't control when the code grows. You should always ask yourself why you don't make this coupling explicit.

    0 讨论(0)
  • 2021-02-06 01:16

    The difference between options 2 and 3 is that in the second case, the function will be internal to the translation unit. If the function is only defined in the cpp this should be the option (which is roughly equivalent to an unnamed namespace --which is a fourth option to consider, again roughly equivalent to 3).

    If the function is to be used by different translation units then you should go with option 2. The function will be compiled once (unless you mark it as inline and provide the definition in the header), while with option 3 the compiler will create it's an internal copy in each translation unit.

    As of option 1, I would avoid it. In Java or C# you are forced to use classes everywhere, and you end up with utility classes when operations do not nicely map to the object paradigm. In C++ on the other hand, you can provide those operations as free standing functions, and there is no need to add the extra layer. If you opt for the utility class, don't forget to disable the creation of the objects.

    Whether the functions are at class or namespace level will affect the lookup, and that will impact on user code. Static member functions need to be qualified with the class name always, unless you are inside the class scope, while there are different ways of bringing namespace functions into scope. As an illustrative example, consider a bunch of math helper functions, and calling code:

    double do_maths( double x ) {
       using namespace math;
       return my_sqrt( x ) * cube_root(x);
    }
    // alternatively with an utility class:
    double do_maths( double x ) {
       return math::my_sqrt(x) * math::cube_root(x);
    }
    

    Which one you find easier to read is a different story, but I prefer the former: within the function I can select the namespace and then just focus on the operations and ignore lookup issues.

    0 讨论(0)
  • 2021-02-06 01:17

    I use struct with static functions, because it offers a slighly better isolation than non-member functions in namespaces (due to the avoidance of Koenig lookup).

    To give an example of the thing I want to avoid:

    namespace Foo
    {
          struct A
          {
          };
    
          void f(const A& a) {}
    }
    
    void f(const Foo:A& a) { std::cout << "AAA"; }
    
    int main(void)
    {
          Foo::A a;
          f(a); // calls Foo:f
          return 0;
    }
    
    0 讨论(0)
提交回复
热议问题