Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can C++ free functions be aliased?

I have a namespace with one highly templated free function, such as:

namespace a
{
    template<typename T, typename K, typename H>
    void f(T t, K k, std::vector<H> h_vec = {})
    { /* body */ }
}

Inside another namespace, for convenience I would like to have some aliases of it for a bunch of specific usages, such has:

namespace b
{
    using my_specific_f = a::f<int,string,char>;
}

Which would allow me to provide a better naming for the function, since f is very generic in the code base I am working on (please keep in mind I am providing only simplified examples here to make the point). But unfortunately, this is apparently forbidden by the language.

So in my second attempt I tried to use a function pointer:

namespace b
{
    auto my_specific_f = &a::f<int,string,char>
}

This would normally work, but in my case it does not since f has one defaulted parameter, which I guess leads to the function having more than one function pointer (in this case two), and only the three parameter version can be used.

At this point I just gave up and simply made my_specific_f redirect the call in its body to f:

namespace b
{
    void my_specific_f(int i, string s, vector<char> v = {} )
    {
        a::f(i,s,v);
    }
}

But this solution I do not really like, as it leads to less maintainability in case f will change its signature since all the redirecting functions need to be adapted concordantly, and my original plan was to create more than just one alias.

Is there anything left I could try? Is it even possible or will it be possible in some future release of the standard?

like image 519
nyarlathotep108 Avatar asked Dec 24 '22 00:12

nyarlathotep108


1 Answers

What you can do is wrap the fucntion in a generic lambda so you can give it a custom name. You can do that like

auto my_really_informative_name = [](auto&&... args) -> decltype(auto) { 
                                      return f(std::forward<decltype(args)>(args)...);
                                  };

This perfectly forwards the parameters to f and if it's signature ever changes it will still work since the lambda can take any number of arguments.

If you want to to be perfectly forwarding (noexcecpt qualification and return type in a SFINAE way)

auto my_really_informative_name = [](auto&&... args) noexcept(noexcept(f(std::forward<decltype(args)>(args)...))) -> decltype(f(std::forward<decltype(args)>(args)...)) { 
                                      return f(std::forward<decltype(args)>(args)...);
                                  };

If you want to make sure the types passed to the function are of a certain type then you can specify them explicitly in the function call like

auto my_really_informative_name = [](auto&&... args) -> decltype(auto) { 
                                      return f<int, std::string, char>(std::forward<decltype(args)>(args)...);
                                  };
like image 93
NathanOliver Avatar answered Jan 02 '23 23:01

NathanOliver