名前空間barにクラス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は間接的なポインタとして効果的に実装できます。「エイリアスされていない」Aは「即時のセマンティクス」を使用できます。
完全な転送を使用して、関数エイリアスを定義することができます(多少の作業が必要です)。
template <typename... Args>
auto g(Args&&... args) -> decltype(f(std::forward<Args>(args)...)) {
return f(std::forward<Args>(args)...);
}
このソリューションは、f
がオーバーロードされている場合や、関数テンプレートが適用されている場合でも適用されます。
クラスはtypesであるため、typedef
およびusing
(C++ 11の場合)でエイリアスできます。
関数はobjectsに非常に似ているため、それらをエイリアスするメカニズムはありません。せいぜい関数ポインタまたは関数参照を使用できます:
void (*g)() = &bar::f;
void (&h)() = bar::f;
g();
h();
同様に、エイリアスを作成するメカニズムはありません変数(スルーポインターまたは参照)。
絶対に:
#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
>
参照は、既存のオブジェクトへのエイリアスです。
関数への参照を作成しました。参照は、元のオブジェクトとまったく同じ方法で使用できます。
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 で生成されました。
名前を変更せずに関数を別のスコープに導入することは可能です。したがって、異なる修飾名で関数をエイリアスできます。
namespace bar {
void f();
}
namespace baz {
using bar::f;
}
void foo() {
baz::f();
}
標準の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();
}