С++ 11: Как псевдоним функции? - программирование
Подтвердить что ты не робот

С++ 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 может использовать "непосредственную семантику".

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

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

g();
h();

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

Ответ 3

Абсолютно:

#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
>

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

Ответ 4

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

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

Это создает символ f как псевдоним для __f. С VС++ вы делаете то же самое:

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

Ответ 5

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

namespace bar {
  void f();
}

namespace baz {
  using bar::f;
}

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

Ответ 6

constexpr функции 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.

Ответ 7

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

namespace bar
{
    void f();
}

#define f bar::f

int main()
{
    f();
}