C++11: как создать псевдоним функции?

Если у меня есть класс Foo в строке пространства имен:

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

Я могу тогда:

using Baz = bar::Foo;

и теперь это так же, как я определил класс в своем пространстве имен с именем Baz.

Можно ли сделать то же самое для функций?

namespace bar
{
    void f();
}

А потом:

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

Какой самый чистый способ сделать это?

Решение должно также выполняться для шаблонных функций.

Определение: если какая-то сущность B является псевдонимом A, то если какое-либо или все использования (не, конечно, объявления или определения) A заменяются на B в исходном коде, то сгенерированный (раздетый) код остается тем же. Например typedef A B это псевдоним. #define B A это псевдоним (по крайней мере). T& B = A не является псевдонимом, B может эффективно реализовываться как косвенный указатель, тогда как "unaliased" A может использовать "непосредственную семантику".

7 ответов

Решение

Вы можете определить псевдоним функции (с некоторой работой), используя совершенную пересылку:

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

Это решение действительно, даже если f перегружен и / или шаблон функции.

constexpr указатель функции может использоваться как псевдоним функции.

namespace bar
{
    int f();
}

constexpr auto g = bar::f;

Там, где используется псевдоним, компилятор будет вызывать функцию с псевдонимом даже при компиляции без каких-либо оптимизаций.

С GCC7 следующее использование

int main()
{
    return g();
}

становится

main:
  push rbp
  mov rbp, rsp
  call bar::f()  # bar::f() called directly.
  pop rbp
  ret

Сборка была сгенерирована в Compiler Explorer.

Классы являются типами, поэтому они могут быть связаны с typedef а также using (в C++11).

Функции гораздо больше похожи на объекты, поэтому нет механизма для их псевдонима. В лучшем случае вы можете использовать указатели на функции или ссылки на функции:

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

g();
h();

В том же духе, нет механизма для псевдонимов переменных (если не считать через указатели или ссылки).

Можно ввести функцию в другую область без изменения ее имени. Таким образом, вы можете создать псевдоним функции с другим квалифицированным именем:

namespace bar {
  void f();
}

namespace baz {
  using bar::f;
}

void foo() {
  baz::f();
}

Абсолютно:

#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);
}

Пытаться:

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

Ссылка - это псевдоним существующего объекта.
Я только что создал ссылку на функцию. Ссылка может использоваться точно так же, как и исходный объект.

Это не стандартный C++, но большинство компиляторов предоставляют такой способ. С GCC вы можете сделать это:

void f () __attribute__ ((weak, alias ("__f")));

Это создает символ f как псевдоним для __f, С VC++ вы делаете то же самое следующим образом:

#pragma comment(linker, "/export:f=__f")

Вы можете использовать старые добрые макросы

namespace bar
{
    void f();
}

#define f bar::f

int main()
{
    f();
}
Другие вопросы по тегам