关于在不可修改模板函数中使用双成员变量结构体的技术疑问
问题1:结构体C是否合法?是否应避免这种写法?
你的C是合法的C++代码:
- C++11及以后支持非静态成员的就地初始化(
float first_ = global;); - 函数内部定义的局部结构体允许访问外部函数的静态变量;
- 它完全满足
cannot_change对模板参数B的要求:有单参数float构造函数,重载了operator()返回float。
要不要避免取决于场景:
- 若
global仅用来初始化C的first_,且不会被其他代码修改,这种写法没问题; - 但
global是静态变量,一旦被其他代码修改,所有C实例的first_都会受影响,存在全局状态风险; - 另外,
C是局部结构体,只能在main内部使用,无法复用,这是个局限。
问题2:除静态变量外,还有哪些方式给C的first_赋值?
你去掉static编译报错的核心原因是:C++不允许局部类(函数内定义的类)访问外部函数的非静态局部变量。要绕开这个限制,同时满足cannot_change的调用要求,有以下几种方案:
方案1:Lambda表达式(推荐)
Lambda可以捕获外部非静态变量的副本,自动生成符合要求的函数对象,无需手动写结构体:
template <typename B> float cannot_change(float second) { B b(second); return b(); } int main() { float first_val = 10; // 不需要static auto calc_obj = [first = first_val](float second) { return first * second; }; std::cout << cannot_change<decltype(calc_obj)>(20) << std::endl; }
这里lambda通过值捕获first_val的副本,生成的匿名函数对象完全适配cannot_change的模板要求,没有全局状态的问题。
方案2:带模板参数的结构体
把first_的值作为模板参数传入,编译期确定该值:
template <typename B> float cannot_change(float second) { B b(second); return b(); } template <float FirstVal> struct C { float second_; C(float second) : second_(second) {} float operator()() { return FirstVal * second_; } }; int main() { std::cout << cannot_change<C<10>>(20) << std::endl; }
这种方式性能较好(FirstVal是编译期常量),但first_的值必须在编译期确定,无法动态修改。
方案3:全局结构体+构造函数默认参数
如果first_的值固定,可以把C移到全局作用域,用默认参数初始化first_:
template <typename B> float cannot_change(float second) { B b(second); return b(); } struct C { float first_; float second_; C(float second, float first = 10) : first_(first), second_(second) {} float operator()() { return first_ * second_; } }; int main() { std::cout << cannot_change<C>(20) << std::endl; }
局限性是first_的默认值固定,无法动态调整,若要修改first_的值,就需要破坏cannot_change的调用规则。
内容的提问来源于stack exchange,提问作者fabian
相关产品推荐
相关产品推荐

