如何在C++17中检查类型是否支持二元结构化绑定?
实现C++17的
is_structured_bindable_2<T>模板 C++17中无法直接在SFINAE的表达式上下文里写语句,但可以通过立即调用的lambda表达式在decltype中模拟结构化绑定语句,从而利用SFINAE判断该语句是否合法。以下是完整实现:
完整代码
#include <type_traits> #include <utility> // 用于测试std::pair,可选 namespace detail { // 重载1:当结构化绑定语句合法时匹配 template<typename T> auto test_bind(int) -> decltype( // 立即调用lambda,内部执行目标结构化绑定语句 []() { // 使用std::declval<T>()避免要求T必须默认可构造 auto [f1, f2] = std::declval<T>(); }(), std::true_type{} ); // 重载2:结构化绑定语句不合法时匹配 template<typename T> std::false_type test_bind(...); } // 主模板:默认返回false_type template<typename T, typename = void> struct is_structured_bindable_2 : std::false_type {}; // SFINAE特化:当test_bind返回true_type时生效 template<typename T> struct is_structured_bindable_2<T, std::void_t<decltype(detail::test_bind<T>(0))>> : decltype(detail::test_bind<T>(0)) {}; // 变量模板,方便直接使用 template<typename T> inline constexpr bool is_structured_bindable_2_v = is_structured_bindable_2<T>::value;
实现原理
detail::test_bind的第一个重载通过decltype包裹了一个立即执行的lambda,lambda内部执行用户要检查的auto [f1, f2] = std::declval<T>();语句:- 用
std::declval<T>()生成T类型的右值引用,避免要求T必须具备默认构造函数,覆盖更多使用场景。
- 用
- 如果结构化绑定语句合法,lambda可以被正常实例化,重载1会被选中,返回
std::true_type;否则重载1会因SFINAE规则被排除,匹配重载2返回std::false_type。 - 主模板通过
std::void_t捕获test_bind<T>(0)的类型,触发SFINAE机制,自动选择正确的特化版本。
测试示例
// 测试用例结构体 struct TwoMemberAggregate { int a; double b; }; struct ThreeMemberAggregate { int a; double b; char c; }; struct TupleLikeType { template<std::size_t I> auto&& get() &&; }; // 为TupleLikeType实现tuple协议 namespace std { template<> struct tuple_size<TupleLikeType> : std::integral_constant<std::size_t, 2> {}; } int main() { // 数组类型检查 static_assert(is_structured_bindable_2_v<int[2]>); static_assert(!is_structured_bindable_2_v<int[3]>); // 聚合类型检查 static_assert(is_structured_bindable_2_v<TwoMemberAggregate>); static_assert(!is_structured_bindable_2_v<ThreeMemberAggregate>); // Tuple-like类型检查(实现tuple协议) static_assert(is_structured_bindable_2_v<TupleLikeType>); static_assert(is_structured_bindable_2_v<std::pair<int, std::string>>); // 普通类型检查 static_assert(!is_structured_bindable_2_v<int>); static_assert(!is_structured_bindable_2_v<double>); }
注意事项
- 该方案完全模拟了
auto [f1, f2] = x;的编译行为,覆盖了所有结构化绑定的合法场景:固定大小数组、聚合类型、实现tuple协议的类类型。 - 使用
std::declval<T>()确保即使T是不可默认构造的类型(如没有默认构造函数的类),也能正常进行检查。
内容的提问来源于stack exchange,提问作者Drdilyor
相关产品推荐
相关产品推荐

