C ++で関数名にエイリアスを割り当てるにはどうすればよいですか?


100

型、変数、名前空間の新しい名前を作成するのは簡単です。しかし、関数に新しい名前を割り当てるにはどうすればよいですか?例えば、私は名前を使用したいhollerためprintf。#defineは明白です...他の方法?

ソリューション:

  1. #define holler printf
  2. void (*p)() = fn; //function pointer
  3. void (&r)() = fn; //function reference
  4. inline void g(){ f(); }

あなた方全員に感謝します。私の同僚はつもり愛、それは見ているvoid (&NewName)(some_vector&, float, float, float, float) = OldName;中で、私の横のチェックで。
Agnel Kurian氏

19
標準のライブラリ関数にランダムな名前を使用するのが好きになるほどで​​はありません。
jalf

2
私はprintfここをいじりません。それはほんの一例でした。ここでの問題は、何よりも英語の制限に関係しています。目的Aと目的Bに対応する単一の機能がありますが、ここでは両方の目的に対応する単一の名前を見つけることができません。
Agnel Kurian

2
@ニール、正確に。T &a = b;の新しい名前を作成しbます。typedefタイプおよびnamespace A=B;ネームスペース。
Agnel Kurian 2010年

2
ありusing BaseClass::BaseClassMethod、そこにあるusing AliasType = Type;、とさえありますnamespace AliasNamespace = Namespace;。欠けているのはusing AliasFunction = Function;
anton_rh 2018年

回答:


114

さまざまなアプローチがあります。

  • テンプレート以外のオーバーロードされていない関数を使用するC ++ 11では、次のように簡単に使用できます。

    const auto& new_fn_name = old_fn_name;
  • この関数に複数のオーバーロードがある場合は、次を使用する必要がありますstatic_cast

    const auto& new_fn_name = static_cast<OVERLOADED_FN_TYPE>(old_fn_name);

    例:関数には2つのオーバーロードがあります std::stoi

    int stoi (const string&, size_t*, int);
    int stoi (const wstring&, size_t*, int);

    最初のバージョンのエイリアスを作成する場合は、以下を使用する必要があります。

    const auto& new_fn_name = static_cast<int(*)(const string&, size_t*, int)>(std::stoi);

    注:オーバーロードされたすべてのバージョンが機能するように、オーバーロードされた関数にエイリアスを作成する方法はないため、常に、どの関数オーバーロードが必要かを正確に指定する必要があります。

  • C ++ 14では、constexprテンプレート変数をさらに使用できます。これにより、テンプレート関数のエイリアスを作成できます。

    template<typename T>
    constexpr void old_function(/* args */);
    
    template<typename T>
    constexpr auto alias_to_old = old_function<T>;
  • さらに、C ++ 11以降では、std::mem_fnメンバー関数にエイリアスを設定できる関数が呼び出されます。次の例を参照してください。

    struct A {
       void f(int i) {
          std::cout << "Argument: " << i << '\n';
       }
    };
    
    
    A a;
    
    auto greet = std::mem_fn(&A::f); // alias to member function
    // prints "Argument: 5"
    greet(a, 5); // you should provide an object each time you use this alias
    
    // if you want to bind an object permanently use `std::bind`
    greet_a = std::bind(greet, a, std::placeholders::_1);
    greet_a(3); // equivalent to greet(a, 3) => a.f(3);

1
C ++ 98はどうですか?設定とリセットに使用される2つの「リセット」オーバーロードを持つクラスがあります。内部的には問題ありません。外部ユーザーの場合は、「セット」としてエイリアスを付けたかったので、コンテキストに対して直感的です(デフォルトで作成された、clear()で設定された、作業オブジェクトをリセットした)。クラスメソッド:(1)「void(&set)(const string&、const bool、const bool);」(2)void(&set)(const string&、const int、const bool); 対応するシグネチャを持つ2つの「リセット」が機能します。私はクラス宣言に署名を持っているので、単にclass-initialize、:set(reset)、set(reset)できますか?そうでない場合、明示的なstatic_castの例は機能しますか?
Luv2code

8
constexprテンプレート変数のアプローチに問題があるようです:エイリアスは型の推論を行うことができません。コンパイラーは、テンプレートパラメーターリストを提供するように私に要求します(私は可変個のテンプレート関数を書いています):テンプレート引数リストなしで変数テンプレート `alias_to_old 'を参照することはできません
user69818

1
constexpr auto new_fn_name = old_fn_nameC ++ 11(少なくともgcc 4.9.2)で動作し、を配置するよりも優れてい&ます。呼び出しが常にポインターを介して行われる必要はないため、呼び出しの代わりに関数をインライン化できます。
オニー2016年

C ++ 14件の一般的なラムダで、私は、次の手順を実行することができたターゲット機能は、複数のオーバーロードがありますときにする必要があり、作業: constexpr auto holler = [] ( auto &&...args ) { return printf( std::forward<decltype(args)>( args )... ); };
アンソニー・ホール

1
を使用することstd::mem_fnは、感覚の背後でより多くの魔法を実行するため、エイリアスではありません
cgsdfc

35

関数ポインタまたは関数参照を作成できます。

void fn()
{
}

//...

void (*p)() = fn;//function pointer
void (&r)() = fn;//function reference

2
これはケーキを取ります。関数参照については知りませんでした。
Agnel Kurian 2010年

@Vulcan:どちらも同じ構文で呼び出すことができるという点でほとんど同じですが、アドレスは少し異なります。rは、アドレスを保持する独自のメモリ空間を占有しません。
ブライアンR.ボンディ

1
fnエイリアスを使用して、どのように呼び出しますか?関数ポインタと関数リファレンスを説明できますか?それらはどう違いますか?ここでは同じですか?
ma11hew28

1
@マット、あなたはそれをfnと同じように呼びます。r();
Agnel Kurian 2012年

インスタンスメソッドに対してこれをどのように行いますか?編集:これはコンパイルされているようです:void (&r)() = this->fn;
サム

21
typedef int (*printf_alias)(const char*, ...);
printf_alias holler = std::printf;

元気ですか。


printfはグローバル名前空間にありませんか?
Agnel Kurian

3
<stdio.h>をインクルードした場合はグローバルですが、<cstdio>をインクルードした場合はstd内
Injektilo 2013

@einpoklum:と何も間違ってありdecltypeが、しかし答えは、2010年戻るからであるし、そこではなかったdecltypeそれはC ++ 11で導入されたとして。さらに、これは、古き良きプレーンCとの仕事もすべきである
Phidelux


7

インラインラッパーを使用します。両方のAPIを取得しますが、単一の実装を維持します。


3

fluentcppから:ALIAS_TEMPLATE_FUNCTION(f、g)

#define ALIAS_TEMPLATE_FUNCTION(highLevelF, lowLevelF) \
template<typename... Args> \
inline auto highLevelF(Args&&... args) -> decltype(lowLevelF(std::forward<Args>(args)...)) \
{ \
    return lowLevelF(std::forward<Args>(args)...); \
}

0

ここでIMOについて言及する価値はあります。元の質問(および優れた回答)は、関数の名前を変更したい場合(そうするのに十分な理由があります!)名前をつけてください、これにはusingキーワードがあります:

namespace deep {
  namespace naming {
    namespace convention {
      void myFunction(int a, char b) {}
    }
  }
}
int main(void){
  // A pain to write it all out every time
  deep::naming::convention::myFunction(5, 'c');

  // Using keyword can be done this way
  using deep::naming::convention::myFunction;
  myFunction(5, 'c');  // Same as above
}

これには、スコープに限定されるという利点もありますが、常にファイルの最上位で使用できます。私は多くの場合、これを使用coutしてendl、私はすべてに持参する必要はありませんので、std古典的でusing namespace std;、ファイルの先頭に、だけでなく、便利なあなたのようなものを使用している場合std::this_thread::sleep_for()、一つのファイルまたは機能の多くではなく、どこでも、および名前空間の他の関数はありません。いつものように、これを.hファイルで使用することはお勧めしません。そうしないと、グローバル名前空間が汚染されます。

これは上記の「名前の変更」と同じではありませんが、たいていは本当に望んでいるものです。


0

C ++ 14ジェネリックラムダを使用して、以下を実行できました。これは、ターゲット関数に複数のオーバーロードがある場合にも機能するはずです。

constexpr auto holler = [] ( auto &&...args ) {
        return printf( std::forward<decltype(args)>( args )... );
    };
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.