Si j'ai une classe Foo dans la barre d'espace de noms:
namespace bar
{
class Foo { ... }
};
Je peux alors:
using Baz = bar::Foo;
et maintenant c'est comme si j'avais défini la classe dans mon espace de noms avec le nom Baz.
Est-il possible de faire de même pour les fonctions?
namespace bar
{
void f();
}
Et alors:
using g = bar::f; // error: ‘f’ in namespace ‘bar’ does not name a type
Quelle est la façon la plus propre de procéder?
La solution doit également tenir pour les fonctions de modèle.
Définition: Si une entité B est un alias de A, alors si certains ou tous les usages (pas les déclarations ou définitions bien sûr) de A sont remplacés par B dans le code source que le code généré (supprimé) reste le même. Par exemple typedef A B
est un alias. #define B A
est un alias (au moins). T& B = A
n'est pas un alias, B peut effectivement être implémenté comme un pointeur indirect, alors qu'un A "sans alias" peut utiliser la "sémantique immédiate".
Vous pouvez définir un alias de fonction (avec un peu de travail) en utilisant un transfert parfait:
template <typename... Args>
auto g(Args&&... args) -> decltype(f(std::forward<Args>(args)...)) {
return f(std::forward<Args>(args)...);
}
Cette solution s'applique même si f
est surchargé et/ou un modèle de fonction.
Les classes sont types, elles peuvent donc être aliasées avec typedef
et using
(en C++ 11).
Les fonctions ressemblent beaucoup plus à objets, il n'y a donc pas de mécanisme pour les alias. Au mieux, vous pouvez utiliser des pointeurs de fonction ou des références de fonction:
void (*g)() = &bar::f;
void (&h)() = bar::f;
g();
h();
Dans la même veine, il n'y a pas de mécanisme d'alias variables (à court de pointeurs ou de références).
Absolument:
#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);
}
Essayer:
> g++ a.cpp
> ./a.out
Test
Test
Test: 3
>
Une référence est un alias vers un objet existant.
Je viens de créer une référence à une fonction. La référence peut être utilisée exactement de la même manière que l'objet d'origine.
Le pointeur de fonction constexpr
peut être utilisé comme alias de fonction.
namespace bar
{
int f();
}
constexpr auto g = bar::f;
À l'endroit où l'alias est utilisé, le compilateur appellera la fonction alias même lors de la compilation sans optimisation.
Avec GCC7, l'utilisation suivante
int main()
{
return g();
}
devient
main:
Push rbp
mov rbp, rsp
call bar::f() # bar::f() called directly.
pop rbp
ret
L'assembly a été généré dans Explorateur du compilateur .
Il est possible d'introduire la fonction dans une portée différente sans changer son nom. Vous pouvez donc alias une fonction avec un nom qualifié différent:
namespace bar {
void f();
}
namespace baz {
using bar::f;
}
void foo() {
baz::f();
}
Ce n'est pas du C++ standard, mais la plupart des compilateurs fournissent un moyen de le faire. Avec GCC, vous pouvez faire ceci:
void f () __attribute__ ((weak, alias ("__f")));
Cela crée le symbole f
comme alias pour __f
. Avec VC++, vous faites la même chose de cette façon:
#pragma comment(linker, "/export:f=__f")
Vous pouvez utiliser de bonnes vieilles macros
namespace bar
{
void f();
}
#define f bar::f
int main()
{
f();
}