c++ 为什么参数Map中的替换失败被认为是病态的?

jgwigjjp  于 2023-02-20  发布在  其他
关注(0)|答案(2)|浏览(118)

this code中,

template<class T, class U>
concept always_true = true;

template<class T>
concept always_true_if_tagged = always_true<T, typename T::tag>;

struct A {
    using tag = int;
};

static_assert(always_true_if_tagged<A>);
static_assert(!always_true_if_tagged<int>);  //GCC says this failed

GCC说第二个Assert失败了,Clang和MSVC都同意编译它。
我最初认为它是病态的,不需要诊断,因为temp.constr.normal#1.4
概念id C<A1, A2, ..., An>的范式是在用A1, A2, ..., An替换每个原子约束中的参数Map中的C的相应模板参数之后,C的约束表达式的范式。如果任何这样的替换导致无效类型或表达式,则程序是病态的;不需要诊断。
代换T::typename tagalways_true的参数Map,因此它是病态的;不需要诊断。
我的前两个问题是
1.* * 我说得对吗?(它是不是格式不对,我的理由是否正确?)
1.* * 为什么它应该是病态的?
(如果我是正确的。)
解决方案之一是先检查嵌套的类型名,这样always_true的参数Map就不会发生。

template<class T>
concept always_true_if_tagged =
    requires {typename T::tag;}
    && always_true<T, typename T::tag>;

此外,温度结构原子#3表示
若要确定是否满足原子约束,首先将参数Map和模板参数替换到其表达式中。**如果替换导致无效类型或表达式,则不满足约束。**否则,如有必要,将执行左值到右值转换。并且E应该是bool类型的常量表达式。当且仅当E的求值结果为true时,满足约束。如果,在程序中的不同点,对于相同的原子约束和模板自变量,满足结果是不同的,程序是病态的,不需要诊断。
如果我写

template<class T>
concept always_true_if_tagged = bool(always_true<T, typename T::tag>);

bool(always_true<T, typename T::tag>)是一个原子约束IIUC,用T=int替换T::typename tag会导致类型无效,因此应该是格式良好的,不能满足。
我最后的两个(或四个)问题是
1.* * 为什么这不适用于第一个代码,或者为什么[temp.constr.normal#1.4]不适用于这里?**

  • 3.1.这个替换是概念id always_true的参数Map吗?
  • 3.2.在concept C = always_true<T, typename T::tag>中使用always_true是原子约束吗?temp. constr. constr #general-1说有三种不同的约束:合取、析取和原子约束。

1.* * 为什么带T=intconcept C = always_true<T, typename T::tag>不能像这个一样是格式良好的?**(可能与第二个问题相同)

d6kp6zgx

d6kp6zgx1#

首先,作用域解析操作符(::)的lhs只能是“命名空间或类、枚举或依赖类型”,否则就是格式错误。
在我的实验中,always_true_if_tagged<int>在gcc编译器中实际上被求值为true,所以static_assert失败是因为求值为false。我猜gcc编译器假设不管T, U如何,always_true总是true,所以在约束规范化中优化了typename T::tag的求值。
所以我对你们问题的回答是:
1.我相信你是对的。
1.编译器不知道约束在此状态下是否满足(约束规范化),并且在概念返回true或false之前无法执行进一步的计算。
1.如上所述,我认为编译器优化了计算。
1.使用概念时发生替换,声明概念时“创建”参数Map,见下文。
1.原子约束
原子约束由表达式E和从E中出现的模板参数到涉及受约束实体的模板参数的模板参数的Map组成,称为其参数Map。
1.我相信你现在有答案了。

o2rvlv0m

o2rvlv0m2#

1.你说对了吗?[...]
是的typename T::tag没有用[T = int]命名一个有效的类型。
1.为什么它应该是病态的?
你引用的理由是正确的。typename int::tag只是没有意义。
在内存中,您还需要将模板专门化移动到struct A之下,以便在template中使用typename A::tag
1.为什么[...]
我不相信这是合式的,因为§ 7.3.2 [conv. lval]
我没有问题的答案,只有更多的问题。
在概念中,它不是模板示例化(请参见:[temp.concept],[temp.spec],[temp.dep]),所以我不明白这怎么可能是原子约束(它是常量表达式吗?它怎么可能求值为任何值)。
clang 14.0.0 doesn’t generate warnings with -fsanitize=undefined on 😰
另见:
SFINAE

相关问题