Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way of renaming (alias/forward) a function in C++?

Tags:

(I'll restrict this question to C++11, since I believe there is no general way to do this in C++98).

Supposed I have a complicated (in terms of signature) set of template functions and/or overloaded functions, and I want to use these functions in the exact same way but using a different name (that is, an alias).

For example:

template<class A, class B, class C> 
D fun(A a, B& b, C&& c){ ... }

template<class E, class F> 
G fun(H<E> he, F& f){ ... }

... many other versions of fun

Now suppose that I want to rename (or alias, or forward to be more precise) these functions, all at once (i.e. be able to use a different name for the same function without rewriting it). Such that, in other parts of the code I can use it with a different name and without modifying the above code.

Is this the correct way to rename (alias/forward) fun into gun?

template<typename... Args> 
inline auto gun(Args&&... args)->decltype(fun(std::forward<Args>(args)...)){
    return fun(std::forward<Args>(args)...);
}
  • Is it truly general?
  • Is this the simplest way?
  • Is this the optimal way? (e.g. can be inlined, no unnecessary copies)
  • What if the original function had some SFINAE features? (e.g. template<class A, class B, class C, class = std::enable_if< ... >::type>), will decltype transfer the SFINAE in all cases?
  • What if the original function returned references? Isn't the decltype going to remove the references type?. (e.g. double& fun(double& x){return x;}).
  • Can same be said about member functions?

Clarification: gun is never going to be exactly fun, as the instances will have different addresses, but what I am looking for is a rename for the point of view of generic coding.

Comment: I find strange that almost everything can be renamed/forwarded, namespaces, types (typedef) and template types using typedef, but not functions (or for that matter member functions).


EDIT: For completeness, and since this seems to be the way to do it, here I added a macro to define function aliases:

#define ALIAS_FUNCTION(OriginalnamE, AliasnamE) \
template <typename... Args> \
inline auto AliasnamE(Args&&... args) -> decltype(OriginalnamE(std::forward<Args>(args)...)) { \
  return OriginalnamE(std::forward<Args>(args)...); \
}

and then you use it like this:

namespace NS1{namepsace NS2{
  ALIAS_FUNCTION(NSA::fun, gun); // second argument (target name can't have namespace)
}}

EDIT2: I think exception policy can be incorporated in the alias as well:

#define ALIAS_FUNCTION(OriginalnamE, AliasnamE) \
template <typename... Args> \
inline auto AliasnamE(Args&&... args) \
  noexcept(OriginalnamE(std::forward<Args>(args)...)) \
->decltype(OriginalnamE(std::forward<Args>(args)...)){\
    return OriginalnamE(std::forward<Args>(args)...);}

but didn't test it yet. You must type it three times.

like image 286
alfC Avatar asked Dec 04 '12 08:12

alfC


1 Answers

Is it truly general?

Yes.

Is this the simplest way?

Yes (sadly).

Is this the optimal way? (e.g. can be inlined, no unnecessary copies)

Yes.

What if the original function had some SFINAE features? (e.g. template<class A, class B, class C, class = std::enable_if< ... >::type>), will decltype transfer the SFINAE in all cases?

Yes, if the expression inside decltype yields an error (i.e., fun doesn't exist, perhaps due to SFINAE on fun), this will trigger SFINAE for gun aswell, removing it from the overload set.

What if the original function returned references? Isn't the decltype going to remove the references type?. (e.g. double& fun(double& x){return x;}).

No, why would it?

Same can be said about member functions, although this has to be done modifying the class I guess.

This isn't a question. What can be said about member functions? All of the above applies equally.

like image 132
Xeo Avatar answered Sep 19 '22 12:09

Xeo