为何模板模板类场景下Concept无法按预期工作?
问题:模板模板参数的Concept约束未按预期生效
我想编写一个类型特征,用来检查容器的内部元素类型是否具备UUID接口。版本V0的实现符合预期,但版本V1虽然能编译,却没有按要求检查Concept,输出结果不符合预期。
示例代码
#include <iostream> #include <vector> struct UUID{}; struct IHaveUUID { UUID GetUUID() { return uuid; } void SetUUID(UUID uuid){ this->uuid = uuid; } UUID uuid; }; struct IDontHaveUUID {}; template <class T> concept HasUUID = requires(T a, UUID uuid) { a.GetUUID(); a.SetUUID(uuid); }; // version 0 template<class T> struct HasUUIDContained_V0 : std::false_type {}; template<template <class U> class T, class U> requires HasUUID<U> struct HasUUIDContained_V0<T<U>> : std::true_type {}; // version 1 template<class T> struct HasUUIDContained_V1 : std::false_type {}; template<template <class U> requires HasUUID<U> class T, class U> struct HasUUIDContained_V1<T<U>> : std::true_type {}; int main() { std::cout<< HasUUIDContained_V0<std::vector<IHaveUUID>>::value << std::endl; // output 1 std::cout<< HasUUIDContained_V0<std::vector<IDontHaveUUID>>::value << std::endl; // output 0 std::cout<< HasUUIDContained_V1<std::vector<IHaveUUID>>::value << std::endl; // output 1 std::cout<< HasUUIDContained_V1<std::vector<IDontHaveUUID>>::value << std::endl; // output 1, what??? I expect 0 too return 0; } // executed in onlinegdb with C++20
原因解析
1. 两个版本的约束位置本质不同
- V0的约束逻辑:
requires HasUUID<U>是对偏特化的整体约束,直接检查当前容器实例的元素类型U是否满足HasUUID概念。当匹配T<U>时,只有U符合要求,才会选中这个偏特化;否则会回退到主模板,返回false_type,这就是为什么vector<IDontHaveUUID>输出0。 - V1的约束逻辑:
template <class U> requires HasUUID<U> class T是对模板模板参数T本身的约束——它要求模板T在定义时,其模板参数U必须满足HasUUID。但std::vector本身并没有这样的内置约束,为什么还能匹配?
2. 模板模板参数的Concept匹配规则
C++20中,带约束的模板模板参数匹配现有模板时,只要现有模板可以被实例化为满足约束的参数,就会判定匹配。也就是说,std::vector虽然没有自带HasUUID约束,但它支持传入满足HasUUID的类型作为元素,因此编译器认为它符合template <class U> requires HasUUID<U> class T的要求。
简单说,V1的约束不是检查你当前传入的U是否满足HasUUID,而是检查容器模板T有没有能力接受满足HasUUID的元素——std::vector显然具备这个能力,所以不管你现在传的U是不是符合,都会匹配这个偏特化,导致vector<IDontHaveUUID>也返回true。
3. 正确的约束位置
如果要检查容器当前使用的元素类型U是否满足Concept,必须像V0那样,将requires HasUUID<U>放在偏特化的模板参数列表之后,作为整个偏特化的约束,而非约束模板模板参数本身。
内容的提问来源于stack exchange,提问作者Jiehong Jiang
相关产品推荐
相关产品推荐

