C ++ 'da bir işlev adına nasıl diğer ad atayabilirim?


100

Bir tür, değişken veya ad alanı için yeni bir ad oluşturmak kolaydır. Ancak bir işleve nasıl yeni bir ad atayabilirim? Örneğin, ben bir ad kullanmak istiyorum holleriçin printf. #define açık ... başka bir yol var mı?

Çözümler:

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

Herkese teşekkürler. Meslektaşlarım bir void (&NewName)(some_vector&, float, float, float, float) = OldName;sonraki check
inimde

19
standart kütüphane işlevleri için rastgele isimler kullandığınızı görmekten hoşlanacakları kadar değil.
jalf

2
printfBurada uğraşmıyorum . Bu sadece bir örnekti. Buradaki problem, her şeyden çok İngilizcenin sınırlamalarıyla ilgilidir. A ve B amacına hizmet eden tek bir işlevim var, ancak burada her iki amaca da hizmet eden tek bir ad bulamıyorum.
Agnel Kurian

2
@Neil, kesinlikle. T &a = b;için yeni bir ad oluşturur b. typedeftürler ve namespace A=B;ad alanları için.
Agnel Kurian

2
Var using BaseClass::BaseClassMethodve var using AliasType = Type;ve hatta var namespace AliasNamespace = Namespace;. Eksik olan şeyusing AliasFunction = Function;
anton_rh

Yanıtlar:


114

Farklı yaklaşımlar var:

  • Şablon olmayan aşırı yüklenmemiş işlevlere sahip C ++ 11 ile şunları kullanabilirsiniz:

    const auto& new_fn_name = old_fn_name;
  • Bu işlevin birden fazla aşırı yüklemesi varsa kullanmalısınız static_cast:

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

    Örnek: işlevin iki aşırı yüklenmesi var std::stoi

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

    İlk sürüme bir takma ad yapmak istiyorsanız, aşağıdakileri kullanmalısınız:

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

    Not: Tüm aşırı yüklenmiş sürümleri çalışacak şekilde aşırı yüklenmiş işlev için bir takma ad yapmanın bir yolu yoktur, bu nedenle her zaman istediğiniz tam işlev aşırı yüklemesini belirtmelisiniz.

  • C ++ 14 ile constexprşablon değişkenleriyle daha da ileri gidebilirsiniz . Bu, şablonlu işlevleri değiştirmenize olanak tanır:

    template<typename T>
    constexpr void old_function(/* args */);
    
    template<typename T>
    constexpr auto alias_to_old = old_function<T>;
  • Dahası, C ++ 11 ile başlayarak std::mem_fnüye işlevlerini takma ad vermenizi sağlayan bir işleve sahipsiniz . Aşağıdaki örneğe bakın:

    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
Mükemmel, C ++ 98'e ne dersiniz? Ayarlamak ve sıfırlamak için kullanılan bir sınıf w / 2 "sıfırlama" aşırı yükleri var. Dahili olarak sorun yok. Harici kullanıcılar için "set" olarak takma ad vermek istedim, böylece bağlam için sezgisel olsun (varsayılan olarak oluşturulmuş, clear () 'd vb. Ayarlayın; çalışma nesnesini sıfırlayın). Sınıf yöntemleri: (1) "void (& set) (const string &, const bool, const bool);" (2) void (& set) (const string &, const int, const bool); 2 "sıfırlama" w / karşılık gelen imzalar işi yapar. Sınıf bildiriminde imzaya sahip olduğum için, sadece sınıf başlatabilir miyim,: set (reset), set (reset). Değilse, açık static_cast örneğiniz işe yarayacak mı?
Luv2code

8
constexprŞablon değişkenleri yaklaşımıyla ilgili bir sorun var gibi görünüyor : diğer ad, tür kesintisi yapamaz. Derleyici, şablon parametre listesi sağlamamı gerektiriyor (bir değişken şablon işlevi yazıyorum): bir şablon bağımsız değişken listesi olmadan değişken şablona `` alias_to_old '' a
başvuramıyorum

1
constexpr auto new_fn_name = old_fn_nameC ++ 11'de çalışır (en azından gcc 4.9.2'de) ve yerleştirmekten daha iyidir &. Çağrının her zaman işaretçi aracılığıyla yapılmasını gerektirmez ve böylece işlevin çağrı yerine satır içine alınmasına izin verir.
ony

C ++ 14 jenerik lambdas ile aşağıdakileri yapabildim, bu da hedef işlevin birden fazla aşırı yüklemesi olduğunda da işe yarayacak: constexpr auto holler = [] ( auto &&...args ) { return printf( std::forward<decltype(args)>( args )... ); };
Anthony Hall

1
Kullanımı std::mem_fnise değil o anlamda arkasında çok daha büyü yapar çünkü bir takma.
cgsdfc

35

Bir işlev işaretçisi veya bir işlev referansı oluşturabilirsiniz:

void fn()
{
}

//...

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

2
Bu pastayı alır. İşlev referanslarını bilmiyordum.
Agnel Kurian

@Vulcan: Her ikisini de aynı sözdizimi ile arayabileceğiniz için hemen hemen aynıdır, ancak adresleri biraz farklıdır. r, bir adres tutan kendi hafıza alanını kullanmaz.
Brian R. Bondy

1
fnTakma adı kullanarak nasıl arayacaksın ? İşlev işaretçisi ve işlev başvurusunu açıklayabilir misiniz? Nasıl farklılar? Burada aynı mı?
ma11hew28

1
@Matt, tam olarak fn olarak adlandırırsınız. r();
Agnel Kurian

bunu bir örnek yöntemi için nasıl yaparsınız? DÜZENLEME: Bu derleme gibi görünüyor:void (&r)() = this->fn;
Sam

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

İyi yapmalısın.


Printf global ad alanında değil mi?
Agnel Kurian

3
<stdio.h> eklediyseniz geneldir, ancak <cstdio>
eklerseniz

@einpoklum: decltype ile ilgili yanlış bir şey yok , ancak cevap 2010'dan. O zamanlar decltypec ++ 11'de sunulduğu gibi yoktu. Üstelik bu, eski güzel sade C ile de çalışmalıdır.
Phidelux


7

Satır içi bir sarmalayıcı kullanın. Her iki API'yi de alırsınız, ancak tek uygulamayı tutarsınız.


3

Kaynaktan 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)...); \
}

1

C ++ 14 genel lambdas ile aşağıdakileri yapabildim, bu da hedef işlevin birden fazla aşırı yüklemesi olduğunda çalışması gerekir:

constexpr auto holler = [] ( auto &&...args ) {
        return printf( std::forward<decltype(args)>( args )... );
    };

Hah! Bu beni üzüyor, başlangıçta sizi bu yanıtı göndermeye iten @ user5534993 bile, daha sonra size olumlu bir oy veremedi. Pekala, benden bir tane al.
FeRD

0

Burada IMO'dan bahsetmeye değer, orijinal soru (ve harika cevaplar) bir işlevi yeniden adlandırmak istiyorsanız kesinlikle yararlı olsa da (bunu yapmak için iyi nedenler var!), Tek yapmak istediğiniz derin bir ad alanını çıkarmaksa adı saklayın, bunun için usinganahtar kelime var :

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
}

Bu aynı zamanda bir kapsamla sınırlı olma avantajına da sahiptir, ancak bunu her zaman bir dosyanın en üst düzeyinde kullanabilirsiniz. Bunu genellikle bunun için kullanıyorum coutve endlbu nedenle TÜMÜNÜ stdklasikle birlikte using namespace std;bir dosyanın üstüne getirmem gerekmiyor , ancak aynı zamanda aşağıdaki gibi bir şey kullanıyorsanız yararlıstd::this_thread::sleep_for() bir dosya veya işlevde çok bir şey , ancak her yerde ve ad alanındaki başka işlevler değil. Her zaman olduğu gibi .h dosyalarında kullanılması tavsiye edilmez, yoksa genel ad alanını kirletersiniz.

Bu, yukarıdaki "yeniden adlandırma" ile aynı şey değildir, ancak genellikle gerçekten istenen şeydir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.