web-dev-qa-db-ja.com

C ++ 11:関数のエイリアス方法は?

名前空間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は「即時のセマンティクス」を使用できます。

61
Andrew Tomazos

完全な転送を使用して、関数エイリアスを定義することができます(多少の作業が必要です)。

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

このソリューションは、fがオーバーロードされている場合や、関数テンプレートが適用されている場合でも適用されます。

63

クラスはtypesであるため、typedefおよびusing(C++ 11の場合)でエイリアスできます。

関数はobjectsに非常に似ているため、それらをエイリアスするメカニズムはありません。せいぜい関数ポインタまたは関数参照を使用できます:

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

g();
h();

同様に、エイリアスを作成するメカニズムはありません変数(スルーポインターまたは参照)。

20
Kerrek SB

絶対に:

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

参照は、既存のオブジェクトへのエイリアスです。
関数への参照を作成しました。参照は、元のオブジェクトとまったく同じ方法で使用できます。

15
Martin York

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 で生成されました。

14
Paweł Bylica

名前を変更せずに関数を別のスコープに導入することは可能です。したがって、異なる修飾名で関数をエイリアスできます。

namespace bar {
  void f();
}

namespace baz {
  using bar::f;
}

void foo() {
  baz::f();
}
10
Jason Haslam

標準のC++ではありませんが、ほとんどのコンパイラはこれを行う方法を提供します。 GCCを使用すると、次のことができます。

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

これにより、__fのエイリアスとしてシンボルfが作成されます。 VC++では、この方法で同じことを行います。

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

古き良きマクロを使用できます

namespace bar
{
    void f();
}

#define f bar::f

int main()
{
    f();
}
1
Romeno