如果所有模板参数都是唯一的,我正在尝试编写一个返回 true 的函数。
伪代码:
template<typename... Ts>
auto types_are_unique() -> bool {
return (no two Ts are the same);
}
而不是“手动”比较每个
T
与其他人一样,我想利用这样一个事实,即如果两个或多个基类相同,则不允许多重继承。#include <utility>
template <typename T>
struct X {};
template <typename... Ts>
struct Test : X<Ts>... {};
template <typename... Ts>
constexpr auto types_are_unique() -> bool {
return false;
}
template <typename... Ts>
requires requires { Test<Ts...>{}; }
constexpr auto types_are_unique() -> bool {
return true;
}
int main() {
static_assert(types_are_unique<int, float>()); // compiles
static_assert(not types_are_unique<int, int>()); // fails
}
gcc 和 clang 都同意这无法编译,因为
unique.cpp:7:8: error: duplicate base type ‘X<int>’ invalid
.这令人惊讶,阅读 https://en.cppreference.com/w/cpp/language/constraints#Requires_expressions
The substitution of template arguments into a requires-expression used in a declaration of a templated entity may result in the formation of invalid types or expressions in its requirements, or the violation of semantic constraints of those requirements. In such cases, the requires-expression evaluates to false and does not cause the program to be ill-formed.
clang 和 gcc 错了吗?还是 cppreference 错误?或者(很可能)我读错了吗?
requires
中不允许出现哪些类的替换失败表达?请参阅 C++20 当前草案的相应部分。
最佳答案
Which classes of substitution failures are not allowed to occur in requires expressions?
和其他地方一样。这实际上并不是特定于概念的。这是您示例的稍微修改版本,它演示了 C++11 的相同问题:
using size_t = decltype(sizeof(0));
template <typename T>
struct X {};
template <typename... Ts>
struct Test : X<Ts>... {};
template <typename...> struct typelist { };
template <typename... T, size_t = sizeof(Test<T...>)>
constexpr auto types_are_unique(typelist<T...>) -> bool {
return true;
}
constexpr auto types_are_unique(...) -> bool {
return false;
}
// ok
static_assert(types_are_unique(typelist<int, float>()));
// compile error
static_assert(not types_are_unique(typelist<int, int>()));
问题与在替代的直接上下文中存在和不存在的内容有关。这是在 [temp.deduct]/8 中引入的术语但并没有真正彻底定义†:
If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression is one that would be ill-formed, with a diagnostic required, if written using the substituted arguments. [ Note: If no diagnostic is required, the program is still ill-formed. Access checking is done as part of the substitution process. — end note ] Only invalid types and expressions in the immediate context of the function type, its template parameter types, and its explicit-specifier can result in a deduction failure. [ Note: The substitution into types and expressions can result in effects such as the instantiation of class template specializations and/or function template specializations, the generation of implicitly-defined functions, etc. Such effects are not in the “immediate context” and can result in the program being ill-formed. — end note ]
一般的想法是只有声明中的失败会导致替换失败,而定义中的失败会导致导致程序格式错误的硬错误。在这里的例子中,问题不在于
Test<int, int>
的声明它在它的定义中(在我们到达它的基类的地方)。这被认为为时已晚——直接上下文之外的失败不再是替代失败。†我们甚至有一个核心问题 ( 1844 ) 要求更好的定义。
关于c++ - 哪些替换失败在 requires 子句中是不允许的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59555623/