如何避免在获取标准库函数地址时出现非标准行为

huangapple go评论61阅读模式
英文:

How to avoid non-standard behavior in taking the address of a standard library function

问题

阅读有关指定可寻址函数的内容后,我意识到获取标准库函数的地址是未定义行为。

现在,我不知道如何重写我的代码,以始终获取标准函数的地址。

#include <iostream>
#include <vector>
#include <cmath>

bool divisible_3(double n){
    return int(n)%3==0;
}

void applyFunction(std::vector<double>& vector, bool(* filterf)(double), double(*calc)(double)){
    for(int index=0;index<int(vector.size());index++){
        if(filterf(vector[index])){
            vector[index]=calc(vector[index]);
        }
    }
}

int main(){
    
    std::vector<double> vect = {1, 2, 3, 5, 9, 16, 21, 24};
    
    applyFunction(vect,divisible_3,std::sqrt);
    
    for(auto&& i: vect){
        std::cout << i << std::endl;
    }

}
英文:

Reading about Designated addressable functions, I realized that taking the address of a standard library function is undefined behavior.

Now, I do not know how to rewrite my code that always take the address of standard functions.

#include &lt;iostream&gt;
#include&lt;vector&gt;
#include&lt;cmath&gt;

bool divisible_3(double n){
	return int(n)%3==0;
}

void applyFunction(std::vector&lt;double&gt;&amp; vector, bool(* filterf)(double), double(*calc)(double)){
	for(int index=0;index&lt;int(vector.size());index++){
		if(filterf(vector[index])){
			vector[index]=calc(vector[index]);
		}
	}
}


int main(){
	
	std::vector&lt;double&gt; vect = {1, 2, 3, 5, 9, 16, 21, 24};
	
	applyFunction(vect,divisible_3,std::sqrt);
	
	for(auto&amp;&amp; i: vect){
		std::cout &lt;&lt; i &lt;&lt; std::endl;
	}

}

答案1

得分: 5

以下是翻译好的部分:

有几种选择。第一种最明显:编写自己的代理函数。 std::sqrt 可能是一个不可寻址的函数,但你知道什么是可寻址的吗?

double totally_not_std_sqrt(double input) {
  return std::sqrt(input);
}

这个函数是完全可寻址的,因此它可以作为参数传递到完全标准的C++中。

另一种更紧凑的选择是使用 lambda 表达式。

applyFunction(vect, divisible_3, [](double x) { return std::sqrt(x); });

现在你可能会想:“lambda 可以转换为 std::function,但我需要一个函数指针”。这是正确的。但是,不捕获的 lambda 可以转换为函数指针,因此即使你的函数接受函数指针,它仍然可以接受不捕获的 lambda 表达式。(不过,除非你打算与C接口交互,否则你可能考虑让你的函数接受 std::function,但这是另一个问题)

英文:

There are a few choices. The first is the most obvious: write your own delegator function. std::sqrt might be a non-addressable function, but you know what is addressable?

double totally_not_std_sqrt(double input) {
  return std::sqrt(input);
}

This function is entirely addressable, so it can be passed in as an argument in completely standard C++.

The other, more compact option is to use a lambda.

applyFunction(vect, divisible_3, [](double x) { return std::sqrt(x); });

Now you might be thinking "lambdas are convertible to std::function, but I take a function pointer". That's true. But lambdas that don't capture are convertible to function pointers, so even though your function takes a function pointer, it can still take non-capturing lambdas. (You might consider having your function take std::function though, unless you're planning on interfacing with C, but that's another issue)

huangapple
  • 本文由 发表于 2023年4月20日 10:42:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/76060137.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定