C++11中非类型模板参数用自定义类报错,如何实现set新元素初始化?
解决C++11中模板非类型参数无法使用自定义类的问题
首先咱们得先搞明白为啥编译报错:在C++11标准里,非类型模板参数的类型有严格限制——只能是算术类型、枚举类型、指针、引用,或者std::nullptr_t这类。你自定义的s类完全不在这个允许的列表里,所以编译器直接拒绝了sample<s, val>这种写法。
那怎么实现你要的「让std::set的新元素初始化为constexpr修饰的自定义类实例」的需求呢?其实没必要非得把val塞进模板参数里,换个思路用构造函数传参就完美解决了,而且完全符合C++11的规则。
修改后的代码示例
#include <set> template <typename T> class sample { public: // 构造函数接收要初始化的常量值 explicit sample(const T& init_val) : _init_val(init_val) {} // 返回val对应的元素(不存在则插入) const T& at(unsigned i) { auto o = _set.insert(_init_val); return *o.first; } private: std::set<T> _set; const T _init_val; // 存储初始化用的常量值 }; class s { public: constexpr s() = default; // 注意:std::set需要元素可比较,所以得给s加operator< bool operator<(const s& other) const { // 这里可以根据实际需求实现比较逻辑,比如比较实例地址(如果实例唯一的话) return this < &other; } }; int main() { constexpr s val; sample<s> o2(val); // 通过构造函数传入constexpr实例 // 测试调用 const auto& elem = o2.at(0); return 0; }
关键修改点说明
- 移除模板非类型参数:把
template <typename T, T val>改成只保留template <typename T>,避开C++11对非类型模板参数的限制。 - 添加构造函数传参:用构造函数接收
const T&类型的初始化值,把它存在sample的成员变量_init_val里。 - 补充
std::set必需的比较运算符:因为std::set的元素必须支持排序,所以给s类加了operator<(你可以根据实际业务逻辑修改这个比较逻辑)。 - 创建实例时传入
constexpr值:main里直接把constexpr s val传给sample<s>的构造函数,完全合法。
额外说明
如果你真的有场景必须用模板参数传递这个值(比如需要编译期确定),在C++11里可以用指针作为非类型模板参数,比如:
// 把val改成全局constexpr变量 constexpr s global_val; template <typename T, const T* val> class sample { // ... 内部逻辑用*val即可 }; // 使用时 sample<s, &global_val> o2;
但这种写法需要变量有全局生命周期,不如构造函数传参的方式灵活优雅,所以更推荐第一种方案。
内容的提问来源于stack exchange,提问作者user3689963
相关产品推荐
相关产品推荐

