C++11: How to alias a function?

51,967

Solution 1

You can define a function alias (with some work) using perfect forwarding:

template <typename... Args>
auto g(Args&&... args) -> decltype(f(std::forward<Args>(args)...)) {
  return f(std::forward<Args>(args)...);
}

This solution does apply even if f is overloaded and/or a function template.

Solution 2

The constexpr function pointer can be used as a function alias.

namespace bar
{
    int f();
}
constexpr auto g = bar::f;

It is highly likely (but not guaranteed by the language) that using g uses bar::f directly. Specifically, this depends on compiler version and optimization level.

In particular, this is the case for:

  • GCC 4.7.1+, without optimization,
  • Clang 3.1+, without optimization,
  • MSVC 19.14+, with optimization.

See assembly generated by these compilers.

Solution 3

Classes are types, so they can be aliased with typedef and using (in C++11).

Functions are much more like objects, so there's no mechanism to alias them. At best you could use function pointers or function references:

void (*g)() = &bar::f;
void (&h)() = bar::f;
g();
h();

In the same vein, there's no mechanism for aliasing variables (short of through pointers or references).

Solution 4

It's possible to introduce the function into a different scope without changing its name. That means that you can alias a function with a different qualified name:

namespace bar {
  void f();
}
namespace baz {
  using bar::f;
}
void foo() {
  baz::f();
}

Solution 5

Absolutely:

#include <iostream>
namespace Bar
{
   void test()
   {
      std::cout << "Test\n";
   }
   template<typename T>
   void test2(T const& a)
   {
      std::cout << "Test: " << a << std::endl;
   }
}
void (&alias)()        = Bar::test;
void (&a2)(int const&) = Bar::test2<int>;
int main()
{
    Bar::test();
    alias();
    a2(3);
}

Try:

> g++ a.cpp
> ./a.out
Test
Test
Test: 3
>

A reference is an alias to an existing object.
I just created a reference to a function. The reference can be used in exactly the same way as the original object.

Share:
51,967
Andrew Tomazos
Author by

Andrew Tomazos

Updated on July 12, 2022

Comments

  • Andrew Tomazos
    Andrew Tomazos 4 months

    If I have a class Foo in namespace bar:

    namespace bar
    {
        class Foo { ... }
    };
    

    I can then:

    using Baz = bar::Foo;
    

    and now it is just like I defined the class in my namespace with the name Baz.

    Is it possible to do the same for functions?

    namespace bar
    {
        void f();
    }
    

    And then:

    using g = bar::f; // error: ‘f’ in namespace ‘bar’ does not name a type
    

    What is the cleanest way to do this?

    The solution should also hold for template functions.

    Definition: If some entity B is an alias of A, than if any or all usages (not declarations or definitions of course) of A are replaced by B in the source code than the (stripped) generated code remains the same. For example typedef A B is an alias. #define B A is an alias (at least). T& B = A is not an alias, B can effectively implemented as an indirect pointer, wheres an "unaliased" A can use "immediate semantics".

  • Andrew Tomazos
    Andrew Tomazos over 10 years
    So what is going on here then: auto g = bar::f; ?
  • Kerrek SB
    Kerrek SB over 10 years
    @user1131467: You declare and define a new object.
  • Andrew Tomazos
    Andrew Tomazos over 10 years
    What is the type of that object? And what is going on here: inline void g() { bar::f(); }
  • Kerrek SB
    Kerrek SB over 10 years
    Bashphorism 2 alert?! That last one defines an entirely new function.
  • Andrew Tomazos
    Andrew Tomazos over 10 years
    What's bashphorism 2? No wait, why is the sky blue? No wait, why is steam coming out your ears? No wait, why are you picking up that axe?
  • Ben Voigt
    Ben Voigt over 10 years
    When defining aliases, I usually like to see them made const. Otherwise a great workaround. This still is quite different from using, however, because it neither pulls in multiple overloads, nor overloads with already-visible definitions with the same name.
  • Admin
    Admin over 10 years
    IIRC, function references work better than function pointers. (but it's been a while since I was playing with this, and I don't know if function references are portable either)
  • Kerrek SB
    Kerrek SB over 10 years
    @Hurkyl: There's no real difference between function references and pointers, as the former always immediately decay into the latter. You can say foo(), (*foo)() and (**foo)() as much as you like.
  • R. Martinho Fernandes
    R. Martinho Fernandes over 10 years
    It doesn't apply if f is a function template that can't use type deduction.
  • Andrew Tomazos
    Andrew Tomazos over 10 years
    @R.MartinhoFernandes: Can you provide an example of such a function template that can't use type deduction?
  • R. Martinho Fernandes
    R. Martinho Fernandes over 10 years
    @user1131467 Any function that uses a template argument to determine its return type (like boost::lexical_cast), or uses a template argument as a de facto argument (like std::get).
  • Andrew Tomazos
    Andrew Tomazos over 10 years
    Doesn't this require an extra dereference when alias is called? Also how does this work for template functions?
  • Martin York
    Martin York over 10 years
    AS you can see it works fine. With templates it works for specific instantiations you can not alias a template but you can alias a specific version of a template.
  • Admin
    Admin over 10 years
    @Kerrek: I recall seeing performance differences when I was testing it. Unfortunately, I cannot recall what precise variations I was experimenting with.
  • Johannes Schaub - litb
    Johannes Schaub - litb over 10 years
    @Kerrek if you say &foo, then you get the address of the function pointer instead of the function. If foo is a reference, this would work correctly and yield the address of the function.
  • Kerrek SB
    Kerrek SB over 10 years
    @JohannesSchaub-litb: It's true that there's a function reference somewhere, but it decays to a function pointer very easily, to the extend that you can keep dereferencing, as each reference immediately decays to a pointer again.
  • Johannes Schaub - litb
    Johannes Schaub - litb over 10 years
    @RMartin if it would assume "ExplicitArgs" to be empty if you don't specify it could rewrite it to template<typename ...ExplicitArgs, typename ...Args> void foo(Args...args) and call the other one like f<ExplicitArgs...>(args...). Unfortunately it only does the "assume-to-be-empty" for a trailing template parameter pack, and not for the one-before-trailing one.
  • Johannes Schaub - litb
    Johannes Schaub - litb over 10 years
    @KerrekSB I am saying that if you have void f(); void (&rf)() = f; then both &f and &rf yield the address of f. But if rf would be a function pointer, void (*rf)() = f;, then &rf returns its address rather than that of the function, which is bad.
  • Johannes Schaub - litb
    Johannes Schaub - litb over 10 years
    @RMartin actually GCC and Clang already do exactly that, so that the above ExplicitArgs way even works in the wild! They consider both template parameter packs "trailing".
  • Kerrek SB
    Kerrek SB over 10 years
    @JohannesSchaub-litb: oh, now I get it. Yes, you're right, references are better in that regard.
  • Richard Smith
    Richard Smith over 10 years
    A better idiom for this is: constexpr auto &alias = Bar::test;. The constexpr part guarantees that the reference will be substituted at compile-time. The auto part won't work for a templated function, though.
  • Steve Jessop
    Steve Jessop over 8 years
    "A reference is an alias to an existing object. I just created a reference to a function." -- and functions are not objects. So references-to-function are not an alias to an existing object (just as function pointers are not object pointers) :-)
  • Martin York
    Martin York over 8 years
    @SteveJessop: What is an object? Is it not something that takes up space in memory? A function occupies space in memory and has an address. So why is it not an object? (At a conceptual level (probably not a language level)).
  • Steve Jessop
    Steve Jessop over 8 years
    @LokiAstari: OK, if you want to use "object" to mean something conceptual, that's different from what it says it means in the standard, that's fine I guess. It will cause confusion among people like me, though who are used to using the language-level definition when talking about C++ :-)
  • Martin York
    Martin York over 8 years
    @SteveJessop: I was trying to use the language level definition. But obviously (as you state) function does not fit that definition in C++. But alias is not a part of the language definition either. Have you a suggestion for better wordage of the above?
  • Steve Jessop
    Steve Jessop over 8 years
    @LokiAstari: I think I've seen "entity" used to mean, roughly, "an object, function, class or member". But of course you can't take a reference to a class, and there's no reference-to-member either. So unfortunately the best term I can think of that's precise, is "object or function". Anyway the questioner is (it turns out) using a special meaning of "alias" and it's not necessarily true that a reference is an alias by that definition, although sometimes it is...
  • einpoklum
    einpoklum over 6 years
    And will this work with overloaded functions, templates, everything?
  • Dennis
    Dennis about 6 years
    I don't know why this isn't the accepted answer: I just tried it and it works, even for template functions (without needing to be prefixed with template <typename> to do so). As far as I can tell it pulls in all of the overloads for the name.
  • Tom
    Tom about 6 years
    @einpoklum Yes - ish. You can make the compiler emit an alias for any concrete function that it generates - they're just entry points in an executable object with names assigned to them, after all. Overloaded functions are just functions, with the name mangled to reflect the function signature. Template functions don't have executable names themselves, but instantiations of those template functions do - and the compiler can emit aliases for them. Whether it's much use to you is another matter.
  • davmac
    davmac about 6 years
    One difficulty with this is that you must use the mangled symbol name for the function in the alias( ) declaration. Your example looks wrong (for this reason); or even if it's correct on some system, it will be much more complicated for a function with parameters..
  • Tom
    Tom about 6 years
    @Davmac: only if you want the alias to be a mangled name. There is nothing wrong with creating an unmangled alias, though it will be of more use from languages other than C++.
  • davmac
    davmac about 6 years
    @Tom I'm not saying the alias will be mangled (or not). It is the symbol that you want to alias to that is problematic. If it is mangled then you must use the mangled name to create the alias. The question asks about creating an alias for bar::foo so you would have to use the mangled name of that symbol when creating the alias. Eg it won't be "__foo", more like "_ZN3bar3fooEv".
  • Tom
    Tom about 6 years
    Ah, yes, true in VC++. The GCC method doesn't require you to name the original symbol, though.
  • davmac
    davmac about 6 years
    @Tom, yes it does. That's what the "__f" (which should be "_ZN3bar3fooEv") is.
  • Johannes Jendersie about 5 years
    The correct and shorter answer which also avoids the problems of ExplicitArgs is given by Jason Haslam below!
  • Michał Fita
    Michał Fita about 5 years
    @RichardSmith you should convert that comment to an answer - it's great!
  • ricab
    ricab over 4 years
    This drops noexcept information and so is not a precise alias in C++17 anymore: coliru.stacked-crooked.com/a/f3ee222a98c97184
  • JVD
    JVD over 4 years
    This is the best solution, but does not work for inlines: namespace bar { static inline __attribute__((always_inline)) void f(); } namespace baz { using bar::f; } void foo() { baz::f(); } $ g++ -g -std=gnu++11 -x c++ -Wall -Wextra -c tns.C x.C:3:8: warning: inline function 'void bar::f()' used but never defined void f(); ^ tns.C: In function 'void foo()': tns.C:3:8: error: inlining failed in call to always_inline '...': function body not available x.C:11:11: error: called from here baz::f();
  • JVD
    JVD over 4 years
    namespace bar { static inline __attribute__((always_inline)) void f(); } namespace baz { using bar::f; } void foo() { baz::f(); }
  • Ignitor
    Ignitor about 3 years
    This can have very unexpected effects depending on the name of the macro. See this answer for reasons (especially the "Macros have no namespace" is dangerous here).
  • Mariusz Jaskółka
    Mariusz Jaskółka over 2 years
    This is the best answer, but you should add that this is not a real alias - compiler actually is allowed to not inline the function call and make a real call. But I believe most compilers will optimize it out, like Compiler Explorer shown.
  • Mariusz Jaskółka
    Mariusz Jaskółka over 2 years
    Macros are old, but nowhere near good in C++.
  • Mariusz Jaskółka
    Mariusz Jaskółka over 2 years
    This answer is partially wrong - it is only a workaround for lack of function aliases in C++. What is more, calling g instead of f may break the ABI, especially if both f and g are a strong symbols.
  • Tom
    Tom over 2 years
    Yep, quite right; in my GCC 9.2.1 this is void f() __attribute__ ((weak, alias("_ZN3bar1fEv")));
  • Unicorn
    Unicorn over 2 years
    You need to take care when using macroses obviously. Every decent C++ programmer knows that. I would not recommend to define such a macro in a header. But in source file it should be fine. With macroses you can always shoot yourself in the foot. If your technology stack permits you probably should use Paweł Bylica's answer. But for older compilers you can consider this solution to ease your life a little bit.
  • Paweł Bylica
    Paweł Bylica over 2 years
    @jaskmar, I updated the answer assuming you meant indirect/direct call instead of inlining. Inlining is not relevant here.
  • Prolight over 2 years
    How do I use this?