The mechanics of extension via free functions or member functions

后端 未结 5 938
挽巷
挽巷 2021-02-14 12:45

Loads of C++ libraries, the standard included, allow you to adapt your objects for use in the libraries. The choice is often between a member function or a free function in the

5条回答
  •  你的背包
    2021-02-14 12:58

    Well, I can tell you how to detect the presence of member functions of a certain name (and signature) at compile time. A friend of mine describes it here:

    Detecting the Existence of Member Functions at Compile-Time

    However that won't get you where you want to go, because it only works for the static type. Since you want to pass a "reference-to-vehicle", there is no way to test if the the dynamic type (the type of the concrete object behind the reference) has such a member function.

    If you settle for the static type though, there is another way to do a very similar thing. It implements "if the user provides an overloaded free function, call it, otherwise try to call the member function". And it goes like this:

    namespace your_ns {
    
    template 
    void your_function(T const& t)
    {
        the_operation(t); // unqualified call to free function
    }
    
    // in the same namespace, you provide the "default"
    // for the_operation as a template, and have it call the member function:
    
    template 
    void the_operation(T const& t)
    {
        t.the_operation();
    }
    
    } // namespace your_ns
    

    That way the user can provide it's own overload of "the_operation", in the same namespace as his class, so it's found by ADL. Of course the user's "the_operation" must be "more specialized" than your default implementation - otherwise the call would be ambiguous. In practice that's not a problem though, since everything that restricts the type of the parameter more than it being a reference-to-const to anything will be "more specialized".

    Example:

    namespace users_ns {
    
    class foo {};
    
    void the_operation(foo const& f)
    {
        std::cout << "foo\n";
    }
    
    template 
    class bar {};
    
    template 
    void the_operation(bar const& b)
    {
        std::cout << "bar\n";
    }
    
    } // namespace users_ns
    

    EDIT: after reading Steve Jessop's answer again, I realize that's basically what he wrote, only with more words :)

提交回复
热议问题