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