C++17下如何仅为浮点型模板类启用默认构造函数
解决方案
在C++17中,可以直接使用requires子句为默认构造函数添加约束,仅当模板参数T为浮点型时启用该构造函数,同时不会影响其他构造函数的正常使用:
#include <limits> #include <type_traits> template <typename T> struct Thing { const T x; Thing(T t) : x(t) {} // 仅当T为浮点型时启用默认构造函数 Thing() requires std::is_floating_point_v<T> : x(std::numeric_limits<T>::quiet_NaN()) {} }; // 使用示例 Thing<double> dt; // 正常编译 Thing<float> ft; // 正常编译 // Thing<int> it1; // 编译错误:无匹配的默认构造函数 Thing<int> it2(3); // 正常编译
为什么之前的写法会导致报错?
你之前尝试的两种SFINAE写法存在以下问题:
- 将
enable_if作为构造函数的模板参数时,默认构造函数会被转为模板构造函数。当T为非浮点型时,该模板构造函数会被SFINAE移除,但部分编译器的重载解析逻辑可能因此出现异常,错误干扰带参数构造函数的调用。 - 将
enable_if作为构造函数的默认参数时,函数签名会变得复杂,容易和其他构造函数的重载逻辑产生冲突,引发不必要的编译错误。
而requires子句是C++17专门为约束函数引入的语法,它直接作用于成员函数,只有当约束条件满足时,该函数才会被纳入类的重载集合。这种写法清晰直观,不会改变构造函数的本质(依然是非模板成员函数),也不会干扰其他构造函数的正常调用。
替代方案(不使用requires)
如果你因某些原因无法使用requires,可以将默认构造函数定义为模板,并通过模板参数的SFINAE约束实现需求,同时避免影响其他构造函数:
#include <limits> #include <type_traits> template <typename T> struct Thing { const T x; Thing(T t) : x(t) {} // 仅当T为浮点型时启用默认构造函数 template <typename U = T, std::enable_if_t<std::is_floating_point_v<U>, int> = 0> Thing() : x(std::numeric_limits<U>::quiet_NaN()) {} };
这种写法通过模板参数U的默认值绑定到T,再用enable_if约束U必须为浮点型,既实现了SFINAE移除构造函数的效果,又不会干扰带参数的构造函数的重载解析。
内容的提问来源于stack exchange,提问作者Mustang
相关产品推荐
相关产品推荐

