130

It's easy to create a new name for a type, a variable or a namespace. But how do I assign a new name to a function? For example, I want to use the name holler for printf. #define is obvious... any other way?

Solutions:

  1. #define holler printf
  2. void (*p)() = fn; //function pointer
  3. void (&r)() = fn; //function reference
  4. inline void g(){ f(); }
Agnel Kurian
  • 57,975
  • 43
  • 146
  • 217
  • 2
    Thanks to all of you. My colleagues are gonna love it seeing `void (&NewName)(some_vector&, float, float, float, float) = OldName;` in my next check in. – Agnel Kurian Jun 16 '10 at 13:30
  • 23
    not as much as they're gonna love seeing you use random names for standard library functions. – jalf Jun 16 '10 at 13:58
  • 4
    I'm not messing with `printf` here. That was only an example. The problem here has more to do with limitations of English than anything else. I have a single function serving purpose A and purpose B but I am simply unable to find a single name serving both purposes here. – Agnel Kurian Jun 16 '10 at 16:59
  • Exactly how do you create an alias for a variable? Unless by that you mean a reference or a pointer. –  Jun 16 '10 at 19:50
  • 2
    @Neil, precisely. `T &a = b;` creates a new name for `b`. `typedef` for types and `namespace A=B;` for namespaces. – Agnel Kurian Jun 17 '10 at 03:41
  • One non-obvious moment with function references and pointers: if you define them in header, they should be declared as `static` or `extern` (with corresponding definition in source file in the latter case) - otherwise you can get "multiple definition" error. Mentioned about this only because we discuss aliases (they usually can be used in headers) in this question. – avtomaton Nov 21 '15 at 00:02
  • 4
    There is `using BaseClass::BaseClassMethod`, and there is `using AliasType = Type;`, and there is even `namespace AliasNamespace = Namespace;`. What we are missing is `using AliasFunction = Function;` – anton_rh Mar 01 '18 at 09:12
  • @anton_rh: True. That was actually considered and mentioned in N1449 "Proposal to add template aliases to C++", http://isocpp.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1449.pdf, afterward section 6. "We also briefly considered non-template aliasing". Sadly not added . – Dwayne Robinson Aug 19 '21 at 02:58

8 Answers8

147

There are different approaches:

  • With C++11 with non-template non-overloaded functions you can simply use:

    const auto& new_fn_name = old_fn_name;
    
  • If this function has multiple overloads you should use static_cast:

    const auto& new_fn_name = static_cast<OVERLOADED_FN_TYPE>(old_fn_name);
    

    Example: there are two overloads of function std::stoi

    int stoi (const string&, size_t*, int);
    int stoi (const wstring&, size_t*, int);
    

    If you want to make an alias to the first version you should use the following:

    const auto& new_fn_name = static_cast<int(*)(const string&, size_t*, int)>(std::stoi);
    

    Note: there is no way to make an alias to overloaded function such that all its overloaded versions work, so you should always specify which exact function overload you want.

  • With C++14 you can go even further with constexpr template variables. That allows you to alias templated functions:

    template<typename T>
    constexpr void old_function(/* args */);
    
    template<typename T>
    constexpr auto alias_to_old = old_function<T>;
    
  • Moreover, starting with C++11 you have a function called std::mem_fn that allows to alias member functions. See the following example:

    struct A {
       void f(int i) {
          std::cout << "Argument: " << i << '\n';
       }
    };
    
    
    A a;
    
    auto greet = std::mem_fn(&A::f); // alias to member function
    // prints "Argument: 5"
    greet(a, 5); // you should provide an object each time you use this alias
    
    // if you want to bind an object permanently use `std::bind`
    greet_a = std::bind(greet, a, std::placeholders::_1);
    greet_a(3); // equivalent to greet(a, 3) => a.f(3);
    
sasha.sochka
  • 14,395
  • 10
  • 44
  • 68
  • 1
    Excellent, how about C++98? I have a class w/2 "reset" overloads used to set & reset. Internally, no problem. For external users I wanted to alias as "set" so it's intuitive for context (set a default-constructed, clear()'d etc.; reset working object). Class methods: (1) "void (&set)(const string&,const bool,const bool);" (2) void (&set)(const string&,const int,const bool); 2 "reset" w/corresponding signatures do the work. Since I have the signature in the class declaration, can I just class-initialize, :set(reset),set(reset). If not, will your explicit static_cast example work? – Luv2code Jul 03 '15 at 21:44
  • 11
    There seems to be a problem with the `constexpr` template variables approach: the alias cannot do type deduction. The compiler requires me to provide template parameter list (I am writing a variadic template function): cannot refer to variable template `alias_to_old' without a template argument list – user69818 Feb 11 '16 at 19:21
  • 1
    `constexpr auto new_fn_name = old_fn_name` works in C++11 (at least in gcc 4.9.2) and is better than placing `&`. It doesn't require call to be always done through pointer and thus allows function to be inlined in place of call. – ony Mar 10 '16 at 14:31
  • With C++14 generic lambdas, I was able to do the following, which should also work when the target function has multiple overloads: `constexpr auto holler = [] ( auto &&...args ) { return printf( std::forward( args )... ); };` – Anthony Hall Dec 07 '16 at 00:33
  • 1
    Using ``std::mem_fn`` is *not* an alias since it performs much more magic behind the sense. – cgsdfc Feb 21 '19 at 12:53
  • @AnthonyHall, [your comment](https://stackoverflow.com/questions/3053561/how-do-i-assign-an-alias-to-a-function-name-in-c#comment69223234_18919937) worked for me using overloaded variadic template functions with C++17. IMHO it deserves to be put in a proper answer to gain more attention and a separate discussion. – user5534993 Apr 28 '20 at 13:52
35

You can create a function pointer or a function reference:

void fn()
{
}

//...

void (*p)() = fn;//function pointer
void (&r)() = fn;//function reference
Brian R. Bondy
  • 339,232
  • 124
  • 596
  • 636
  • 4
    This takes the cake. I didn't know about function references. – Agnel Kurian Jun 16 '10 at 13:25
  • @Vulcan: They are almost the same in that you can call both of them with the same syntax, but their addresses are a little diff. r doesn't take up its own memory space holding an address. – Brian R. Bondy Jun 16 '10 at 13:27
  • 1
    How would you call `fn`, using the alias? Can you explain function pointer & function reference? How are they different? Are they the same here? – ma11hew28 Aug 10 '11 at 17:54
  • 1
    @Matt, You call it exactly as you would call fn. `r();` – Agnel Kurian Jun 28 '12 at 03:02
  • how would you do this for an instance method? EDIT: this seems to compile: `void (&r)() = this->fn;` – Sam Sep 18 '13 at 14:15
  • @Sam, I just wrote my answer, look at it. – sasha.sochka Sep 20 '13 at 15:14
  • @BrianR.Bondy R. Bondy Suppose if I am calling a function in class B from class A, for eg: objectB.foo(); how can I give reference to function foo() in class A ?? – Deepak Dec 18 '14 at 13:29
22
typedef int (*printf_alias)(const char*, ...);
printf_alias holler = std::printf;

Should do you fine.

jer
  • 20,094
  • 5
  • 45
  • 69
  • Isn't printf in the global namespace? – Agnel Kurian Mar 19 '13 at 16:34
  • 3
    it's global if you included , but in std if you included – Injektilo Apr 11 '13 at 08:47
  • @einpoklum: There is nothing wrong with [decltype](https://en.cppreference.com/w/cpp/language/decltype), but the answer is from 2010. Back then there wasn't `decltype` as it was introduced in c++11. Furthermore this should also work with good old plain C. – Phidelux Jan 05 '19 at 19:16
10

int (*holler)(const char*, ...) = std::printf;

MSalters
  • 173,980
  • 10
  • 155
  • 350
7

Use an inline wrapper. You get both APIs, but keep the single implementation.

John
  • 71
  • 1
7

With C++14 generic lambdas, I was able to do the following, which should also work when the target function has multiple overloads:

constexpr auto holler = [] ( auto &&...args ) {
        return printf( std::forward<decltype(args)>( args )... );
    };
Anthony Hall
  • 1,442
  • 2
  • 16
  • 22
  • Hah! That makes me sad, even @user5534993 who originally pushed you to submit this answer, then couldn't throw an upvote your way. Well, here, have one on me. – FeRD Aug 21 '20 at 07:30
6

From fluentcpp : ALIAS_TEMPLATE_FUNCTION(f, g)

#define ALIAS_TEMPLATE_FUNCTION(highLevelF, lowLevelF) \
template<typename... Args> \
inline auto highLevelF(Args&&... args) -> decltype(lowLevelF(std::forward<Args>(args)...)) \
{ \
    return lowLevelF(std::forward<Args>(args)...); \
}
sailfish009
  • 2,561
  • 1
  • 24
  • 31
4

It is worth mentioning here IMO that while the original question (and great answers) are definitely useful if you want to rename a function (there are good reasons to do so!), if all you want to do is strip out a deep namespace but keep the name, there is the using keyword for this:

namespace deep {
  namespace naming {
    namespace convention {
      void myFunction(int a, char b) {}
    }
  }
}
int main(void){
  // A pain to write it all out every time
  deep::naming::convention::myFunction(5, 'c');

  // Using keyword can be done this way
  using deep::naming::convention::myFunction;
  myFunction(5, 'c');  // Same as above
}

This also has the advantage of it being confined to a scope, though you could always use it at the top level of a file. I often use this for cout and endl so I don't need to bring in ALL of std with the classic using namespace std; at the top of a file, but also useful if you're using something like std::this_thread::sleep_for() a lot in one file or function, but not everywhere, and not any other functions from the namespace. As always, it's discouraged to use it in .h files, or you'll pollute the global namespace.

This is not the same as the "renaming" above, but is often what is really wanted.

Kevin Anderson
  • 6,850
  • 4
  • 32
  • 54