简体   繁体   English

包扩展用作概念的非包参数的参数

[英]pack expansion used as argument for non-pack parameter of concept

template<typename T>    concept A = true;
template<typename... T> concept B = A<T...>;

Clang and gcc complains 'pack expansion used as argument for non-pack parameter of concept' at the 2nd line. Clang 和 gcc 在第 2 行抱怨“包扩展用作概念的非包参数的参数”。 MSVC compiles. MSVC 编译。 Are the code well-formed or not?代码格式是否正确?


Here is a more concrete example showing why the question matters.这是一个更具体的例子,说明了为什么这个问题很重要。 Say we want to define a concept with parameter pack called single_integral_or_all_floating_point .假设我们要定义一个带有参数包的概念,称为single_integral_or_all_floating_point It is true if the pack has single integral type or all floating point types.如果包具有单一整数类型或所有浮点类型,则为true It is false otherwise.否则为false

template<typename... T>
concept single_integral_or_all_floating_point =
    std::is_integral<T...>::value ||
    (... && std::is_floating_point<T>::value);

If sizeof...(T) is not 1 , there is a substitution failure on std::is_integral and the 1st constraint is not satisfied.如果sizeof...(T)不是1 ,则std::is_integral上的替换失败并且不满足第一个约束。

Let's say we want to get rid of the old type traits and switch to concepts.假设我们想要摆脱旧的类型特征并切换到概念。 Clang and gcc do not compile with a drop-in replacement like below because of 'pack expansion used as argument for non-pack parameter of concept'. Clang 和 gcc 不会使用如下所示的直接替换进行编译,因为“包扩展用作概念的非包参数的参数”。 MSVC compiles. MSVC 编译。

template<typename... T>
concept single_integral_or_all_floating_point =
    std::integral<T...> || // error: pack expansion used as argument for non-pack parameter of concept
    (... && std::floating_point<T>);

We have to come up a workaround for clang/gcc.我们必须为 clang/gcc 想出一个解决方法。

template<typename... T>
struct only {};

template<typename T>
struct only<T> {
    using type = T;
};

template<typename... T>
concept single_integral_or_all_floating_point =
    std::integral<typename only<T...>::type> ||
    (... && std::floating_point<T>);

So if clang and gcc are correct, it is pretty awkward to use concepts in the similar cases.因此,如果 clang 和 gcc 是正确的,那么在类似情况下使用概念就很尴尬了。

The main issue with your first snippet is that concepts must be able to be normalized, and normalization requires a parameter mapping of each template parameter of an atomic constraint.第一个片段的主要问题是概念必须能够规范化,规范化需要原子约束的每个模板参数的参数映射 The fact that the prototype parameter of A is not used in its constraint seems to be irrelevant to GCC/Clang; A的原型参数未在其约束中使用这一事实似乎与 GCC/Clang 无关; they apparently attempt to create some kind of temporary mapping anyway, which fails since a non-pack cannot map to a pack.他们显然试图创建某种临时映射,但失败了,因为非包不能 map 到包。 Which makes sense IMO, because that would be incompatible in whatever internal system normal forms are expressed in.这在 IMO 中是有道理的,因为这在任何内部系统正常 forms 中都是不兼容的。

Regarding your broader use case, there are certainly more sensible ways to express your constraint, eg explicitly checking sizeof... .关于您更广泛的用例,肯定有更明智的方式来表达您的约束,例如明确检查sizeof... You could also use a variable template, whose template-id would be an atomic constraint and thus not prone to the same problem:您还可以使用一个变量模板,其模板 ID 将是一个原子约束,因此不容易出现同样的问题:

template<typename... T>
concept single_integral_or_all_floating_point =
    std::is_integral_v<T...> ||
    (... && std::floating_point<T>);

Demo . 演示

Your code appears to be well-formed您的代码似乎格式正确

I am able to compile without issue on GCC trunk and Clang trunk (-std=c++20)我能够在 GCC trunk 和 Clang trunk (-std=c++20) 上毫无问题地进行编译

It also supports an empty parameter pack without issue.它还支持没有问题的空参数包。 ( test() in the godbolt.) (神栓中的test() 。)

If this is ill-formed, then GCC, Clang, and MSVC are all wrong, which I am hesitant to believe;如果这是错误的,那么 GCC、Clang 和 MSVC 都是错误的,我不敢相信; The compiler issue you are encountering is likely poor support for concepts in whichever bundled GCC and Clang version you have installed.您遇到的编译器问题可能是对您安装的捆绑版本 GCC 和 Clang 中的概念支持不佳。

See: https://godbolt.org/z/frcdc7PTY参见: https://godbolt.org/z/frcdc7PTY

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM