【问题标题】:Creating a function alias创建函数别名
【发布时间】:2015-05-08 16:22:14
【问题描述】:

编辑:这个问题最初的标题是“Using std::bind to create inline function”,但这并不是我真正想要的:我只是想要一种简单的方法来给函数起别名。

我想将std::chrono::high_resolution_clock::now 公开为独立函数。也就是说,我想做以下事情:

auto current_time = std::bind(std::chrono::high_resolution_clock::now);

不幸的是,由于这是在一个头文件中,它会在链接时导致current_time 的多个定义。有没有办法从std::bind 返回内联函数

【问题讨论】:

  • inline auto current_time() { return std::chrono::high_resolution_clock::now(); } 有什么问题?
  • @T.C.没什么特别的(这是我用作解决方法的方法),我只是碰巧认为它有点难看。我真正喜欢的是函数别名,我们有类型别名的方式;即,using current_time = std::chrono::high_resolution_clock::now; 的行为本质上类似于 #define current_time std::chrono::high_resolution_clock::now,但没有预处理器参与。
  • 对于标题,您始终可以为其提供内部链接。
  • @T.C.我可能会误解你,但重点是在多个翻译单元中公开此功能-因此需要inline
  • 为什么需要内联才能在多个翻译单元中使用?在标头中声明函数,将其非内联定义为对std::chrono::high_resolution_clock::now() 的调用。不知道为什么我什至要对此发表评论......只是继续使用您已经拥有的功能(这不是解决方法,而是解决方案)。

标签: c++ c++11 inline stdbind


【解决方案1】:

如果我想创建一个简单的函数别名,我会这样做

constexpr auto &&now = std::chrono::high_resolution_clock::now;

如果我想创建一个将被内联的完整包装别名

template<typename ... Args>
inline constexpr auto now(Args &&... args) -> decltype(std::chrono::high_resolution_clock::now(std::forward<Args>(args)...)){
    return std::chrono::high_resolution_clock::now(std::forward<Args>(args)...);
}

我之所以在别名定义中使用通用引用auto&amp;&amp;,是因为addressof(now) == addressof(std::chrono::high_resolution_clock::now)的可能性。

在我的运行 G++ 4.9.2 的系统上:

constexpr auto &&now_ref = std::chrono::high_resolution_clock::now;
constexpr auto now_var = std::chrono::high_resolution_clock::now;

template<typename ... Args>
inline constexpr auto now_wrapper(Args &&... args)
    -> decltype(std::chrono::high_resolution_clock::now(std::forward<Args>(args)...)){
    return std::chrono::high_resolution_clock::now(std::forward<Args>(args)...);
}

int main(int argc, char *argv[]){
    std::cout << std::hex << std::showbase;
    std::cout << (uintptr_t)std::addressof(std::chrono::high_resolution_clock::now) << '\n';
    std::cout << (uintptr_t)std::addressof(now_wrapper<>) << '\n';
    std::cout << (uintptr_t)std::addressof(now_var) << '\n';
    std::cout << (uintptr_t)std::addressof(now_ref) << '\n';
}

我得到以下结果:

0x4007c0
0x400a50
0x400ae8
0x4007c0

表明只有auto&amp;&amp; 实际上是函数的直接别名,而所有其他方法都具有某种程度的间接性。 (尽管在编译后它们可能被内联函数调用替换。可能。)

【讨论】:

  • 可能是内联的。
  • 有趣。您能否解释一下为什么使用static&amp;&amp;,因为constexpr auto 足以让它工作?
  • static 定义是这样我在标题中定义时不会遇到多个定义错误(您遇到的问题)。 auto&amp;&amp; 语法实际上与后面带有&amp;&amp; 的常规类型不同,auto&amp;&amp; 实际上被称为“通用引用”。生病留给你阅读。如果你单独使用constexpr auto,你可能会得到一个函数指针,但如果你使用constexpr auto&amp;&amp;,你会得到一个函数的引用,比如addressof(now) == addressof(chrono::high_resolution_clock::now)而不是now == addressof(chrono::high_resolution_clock::now)
  • @NeilKirk 如果你真的需要它,你可以将 [[always_inline]] 添加到函数定义(或非 gcc 等效项)
  • @NeilKirk 否则我不会重新建议第一个想法;)但是对于更多特殊情况,对于 OP 学习第二种方法是有好处的。
【解决方案2】:

我认为无论如何都不会这样做,因为 bind 不是 constexpr。

lambdas 也不是 constexpr-able。

编辑:有这个技巧可以制作类似 constexpr 的 lambda http://pfultz2.com/blog/2014/09/02/static-lambda/

【讨论】:

  • 那个 constexpr 把戏太疯狂了,有点棒。不过,这并不是我所希望的。
【解决方案3】:

添加另一个答案,因为它与您想要的答案完全不同。

在这种情况下,std::bind 不是必需的,因为没有发生“绑定”。

但是我觉得这可能会导致一些令人困惑的问题,因为 current_time 并不是真正的别名,就像使用 decarations 一样。

#include <iostream>
#include <chrono>

using namespace std;

auto constexpr current_time = std::chrono::high_resolution_clock::now;

int main() {
    auto now = current_time();
    cout << std::chrono::system_clock::to_time_t(now) << endl;
    return 0;
}

【讨论】:

  • 我在使用这种方法时遇到多定义链接错误。
  • 您需要创建 current_time 变量 static 或将其放在匿名命名空间中。将其声明为 const 会起作用,因为这会使其隐含静态。
  • 至于使用bind,我以为我在某些时候看到了一个编译错误,表明high_resolution_clock 是一个成员函数,但仔细想想,事实并非如此,所以你是对,bind 似乎也不是正确的方法。
  • const 是一个不错的方法。将其添加到您的答案中,我会接受。
  • 在支持它的编译器上,这个current_time应该可以是constexpr
【解决方案4】:

使用 GCC 可以创建一个“函数别名”,但仅适用于在同一翻译单元中定义并且您知道其错位名称的函数,因此无法可靠地为 std::chrono::high_resolution_clock::now() 做p>

https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html 上查看alias 属性

【讨论】:

  • 有趣。一个标准化/便携的版本会非常好。
  • 不,真的不会。对它的限制非常令人望而却步。它对于兼容性 kluges 很有用,例如修复库中的 ABI 错误,而不是您想要的通用实用程序。
  • 好吧,那么,标准化/便携/不那么禁止的版本会很不错!
【解决方案5】:

保持简单。

const auto current_time = std::chrono::high_resolution_clock::now;

【讨论】:

  • 我认为 tahsmith 对这个答案有意见,但你确实得到了支持。
  • @KyleStrand Doh 太慢了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-11
  • 1970-01-01
相关资源
最近更新 更多