考虑以下代码行:
template <typename B>
float cannot_change(float second) {
B b(second);
return b();
}
int main() {
static float global = 10;
struct C {
float first_ = global;
float second_;
C(float second) : second_(second) {}
float operator()() { return first_ * second_; }
};
std::cout << cannot_change<C>(20) << std::endl;
}
字符串
函数cannot_change
构造了一个模板参数B
,该参数只有一个参数。函数是固定的,不能更改,但我知道它的源代码。假设我想传递一个结构体,它接受两个成员函数(C
)。我创建了一个结构体C
,它使用了静态变量global
。
我有几个问题
- 像我这样写结构体
C
是合法的吗?还是应该避免这样做?这看起来很奇怪,但我想在cannot_change
中使用一个B
类型的元素,并带有两个成员变量。 - 如果这是合法的,是否有其他方法为
C
设置变量first_
?我更喜欢复制变量。删除static
关键字会导致编译错误。
1条答案
按热度按时间bnl4lu3b1#
看起来你正在尝试做的是最好用lambda捕获来完成的,就像这样:
字符串
如果你需要处理一些类的成员,你也可以做一个lambda模板(所以你可以写
const B & b
,而不是float second
,并在函数体中使用b.member
),像这样:型
Godbolt
如果你真的需要用这个接口调用
cannot_change
,那么你可以像这样解决它:型
Godbolt的
与上面的注解不同,您不需要将本地
global
变量存储在静态变量中(这会带来很多麻烦)。相反,它使用lambda来捕获局部变量。lambda函数示例由一个模板
CaptureLambda
结构捕获,该结构是为这个特定的lambda示例化的。此结构提供了一个静态函数,其签名与lambda的函数签名相匹配。最后,
Adapter
结构使用此静态函数的指针示例化,并实现cannot_change
所需的接口B。请注意:
1.由于每个lambda都是不同的类型(即使具有相同的签名),因此
CaptureLambda
静态示例上不会有任何冲突,必须将其设置为用于示例化它的相同lambda。这意味着没有问题,你可以找到与普通的静态变量Adapter
是为这个CaptureLambda
特定示例化的,它可以被编译器完全优化掉。1.我在
CaptureLambda
中使用了std::function<>
,因为我很懒。更好的解决方案是实际复制/移动/引用lambda,以避免std::function
的开销1.如果你的lambda没有捕获,不要麻烦使用
CaptureLambda
,直接在cannot_change
调用中使用Adapter<decltype(f)>
,因为一个没有捕获的lambda可以直接转换为一个函数指针。