[英]What is the difference between pointer to function and pointer to WINAPI function?
[英]what's the difference between the function pointer getting from std::function::target<>() and normal function pointer?
以下代碼是從APUE復制的信號實現,稍作修改
namespace
{
using signal_handler = void (*)(int);
signal_handler signal(sigset_t sig, signal_handler);
}
Signal::signal_handler Signal::signal(sigset_t sig, void (*handler)(int))
{
struct sigaction newAction, oldAction;
sigemptyset(&newAction.sa_mask);
newAction.sa_flags = 0;
newAction.sa_handler = handler;
if (sig == SIGALRM)
{
#ifdef SA_INTERRUPT
newAction.sa_flags |= SA_INTERRUPT;
#endif
}
else
{
newAction.sa_flags |= SA_RESTART;
}
if (sigaction(sig, &newAction, &oldAction) < 0)
throw std::runtime_error("signal error: cannot set a new signal handler.")
return oldAction.sa_handler;
}
上面的代碼在我的測試中運行正常,但我想讓它更像C ++代碼,所以我將signal_handler別名更改為
using signal_handler = std::function<void (int)>;
我也用
newAction.sa_handler = handler.target<void (int)>();
取代
newAction.sa_handler = handler;
現在有一個問題。 我發現newAction.sa_handler之后仍然是NULL
newAction.sa_handler = handler.target<void (int)>();
但我不知道為什么。 有人可以幫我解釋一下嗎? 謝謝。 這是我的測試代碼:
void usr1_handler(int sig)
{
std::cout << "SIGUSR1 happens" << std::endl;
}
void Signal::signal_test()
{
try
{
Signal::signal(SIGUSR1, usr1_handler);
}
catch (std::runtime_error &err)
{
std::cout << err.what();
return;
}
raise(SIGUSR1);
}
即使在Xcode中運行時使用原始代碼,也沒有輸出。 相反,我手動運行可執行文件,我可以看到SIGUSR1發生在終端中。 為什么? 如何使用Xcode查看輸出?
直接的答案是target()
非常挑剔 - 你必須准確地命名目標的類型以獲得指向它的指針,否則你得到一個空指針。 當你將信號設置為usr1_handler
,這是一個指向函數(不是函數)的指針 - 它的類型是void(*)(int)
,而不是void(int)
。 所以你只是給target()
提供了錯誤的類型。 如果你改變:
handler.target<void (int)>();
至
handler.target<void(*)(int)>();
這會給你正確的目標。
但請注意target()
實際返回的內容:
template< class T >
T* target();
它返回一個指向所提供類型的指針 - 在這種情況下,它將是一個void(**)(int)
。 在進一步分配之前,您需要取消引用。 就像是:
void(**p)(int) = handler.target<void(*)(int)>();
if (!p) {
// some error handling
}
newAction.sa_handler = *p;
演示 。
然而,真正的答案是這樣做沒有多大意義。 std::function<Sig>
是為給定的Sig
可擦除的類型 - 它可以是指向函數的指針,指向成員函數的指針,甚至是任意大小的包裝函數對象。 這是一個非常通用的解決方案。 但sigaction
不接受任何類型的泛型可調用 - 它特別接受void(*)(int)
。
通過創建簽名:
std::function<void(int)> signal(sigset_t sig, std::function<void(int)> );
你正在創造一種你允許任何可贖回的錯覺! 所以,我可能會嘗試傳遞類似的東西:
struct X {
void handler(int ) { ... }
};
X x;
signal(SIGUSR1, [&x](int s){ x.handler(s); });
你的簽名允許這樣做 - 我提供了一個可以調用int
的調用。 但是那個callable不能轉換為函數指針,所以它不是你可以傳遞給sigaction()
,所以這只是錯誤的代碼永遠無法工作 - 這是一個保證運行時失敗。
更糟糕的是,我可能會傳遞一些可轉換為函數指針的東西,但可能不知道那就是你需要的東西,所以我給你錯了:
// this will not work, since it's not a function pointer
signal(SIGUSR1, [](int s){ std::cout << s; });
// but this would have, if only I knew I had to do it
signal(SIGUSR1, +[](int s){ std::cout << s; });
由於sigaction()
將你限制為只是函數指針,所以你應該將它的接口限制為只是函數指針。 非常喜歡你以前擁有的東西。 使用類型系統來捕獲錯誤 - 只在有意義時才使用類型擦除。
這里有一個例子,可以幫助您理解機制。
#include <iostream>
#include <string>
#include <functional>
void printMyInt(int a)
{
std::cout << "This is your int " << a;
}
int main()
{
std::function<void(int)> f = printMyInt;
void (*const*foo)(int) = f.target<void(*)(int)>();
(*foo)(56);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.