如何在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;在我的下一个签到。
阿涅尔Kurian说

19
不像他们希望看到的那样,您会为标准库函数使用随机名称。
jalf

2
我不会在printf这里弄乱。那只是一个例子。这里的问题更多是与英语的局限性有关。我有一个服务于目的A和目的B的功能,但是我根本无法在这里找到一个同时服务于这两个目的的名称。
Agnel Kurian 2010年

2
@尼尔,正好。T &a = b;为创建新名称btypedef用于类型和namespace A=B;名称空间。
Agnel Kurian 2010年

2
using BaseClass::BaseClassMethod,有using AliasType = Type;,甚至有namespace AliasNamespace = Namespace;。我们缺少的是using AliasFunction = Function;
anton_rh '18

Answers:


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);

    示例:函数有两个重载 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怎么样?我有一个w / 2类“重置”重载,用于设置和重置。内部,没问题。对于外部用户,我想将别名设置为“ set”,以便上下文直观(设置默认构造的,clear()等;重置工作对象)。类方法:(1)“ void(&set)(const string&,const bool,const bool);” (2)void(&set)(const string&,const int,const bool); 2个带有相应签名的“重置”功能。因为我在类声明中有签名,所以我可以只对类进行初始化::set(reset),set(reset)。如果没有,您的显式static_cast示例是否可以工作?
Luv2code 2015年

8
constexpr模板变量方法似乎存在问题:别名不能进行类型推导。编译器要求我提供了模板参数列表(我写一个可变参数模板功能):不能引用变量模板`alias_to_old”没有一个模板参数列表
user69818

1
constexpr auto new_fn_name = old_fn_name在C ++ 11中工作(至少在gcc 4.9.2中),并且比放置更好&。它不需要始终通过指针完成调用,因此可以内联函数来代替调用。
2016年

使用C ++ 14通用lambda,我能够执行以下操作,当目标函数具有多个重载时,它们也应工作: constexpr auto holler = [] ( auto &&...args ) { return printf( std::forward<decltype(args)>( args )... ); };
Anthony Hall

1
使用std::mem_fn不是一个别名,因为它执行背后的意义更为神奇。
cgsdfc

35

您可以创建函数指针或函数引用:

void fn()
{
}

//...

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

2
这需要蛋糕。我不知道函数引用。
Agnel Kurian 2010年

@Vulcan:它们几乎是相同的,因为您可以使用相同的语法来调用它们,但是它们的地址略有不同。r不会占用它自己的存储空间来保存地址。
Brian R. Bondy 2010年

1
您将如何fn使用别名调用?您能解释一下函数指针和函数参考吗?它们有何不同?他们在这里一样吗?
ma11hew28 2011年

1
@Matt,您将其称为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>
则为

@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
}

尽管您总是可以在文件的顶层使用它,但它也具有将其限制在范围内的优势。我经常使用它coutendl所以我不需要将所有std经典using namespace std;文件都放在文件的顶部,但是如果您std::this_thread::sleep_for()在一个文件或函数中使用很多东西,但又不是在所有地方都使用时,这也很有用。没有名称空间中的任何其他函数。与往常一样,不建议在.h文件中使用它,否则将污染全局名称空间。

这与上面的“重新命名”不同,但通常是真正需要的。


0

使用C ++ 14通用lambda,我能够执行以下操作,当目标函数具有多个重载时,它们也应该起作用:

constexpr auto holler = [] ( auto &&...args ) {
        return printf( std::forward<decltype(args)>( args )... );
    };
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.