C ++ 20概念:当template参数符合多个概念时,会选择哪种模板专业化? [英] C++20 Concepts : Which template specialization gets chosen when the template argument qualifies for multiple concepts?

查看:81
本文介绍了C ++ 20概念:当template参数符合多个概念时,会选择哪种模板专业化?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出:

#include <concepts>
#include <iostream>

template<class T>
struct wrapper;

template<std::signed_integral T>
struct wrapper<T>
{
    wrapper() = default;
    void print()
    {
        std::cout << "signed_integral" << std::endl;
    }
};

template<std::integral T>
struct wrapper<T>
{
    wrapper() = default;
    void print()
    {
        std::cout << "integral" << std::endl;
    }
};

int main()
{
    wrapper<int> w;
    w.print(); // Output : signed_integral
    return 0;
}

从上面的代码中, int 符合 std :: integral std :: signed_integral 的概念。

From code above, int qualifies to both std::integral and std::signed_integral concept.

令人惊讶的是,它可以在GCC和MSVC编译器上编译并打印 signed_integral。我期望它会因模板专业化已定义而失败,并出现错误。

Surprisingly this compiles and prints "signed_integral" on both GCC and MSVC compilers. I was expecting it to fail with an error along the lines of "template specialization already been defined".

好的,这是合法的,很公平,但是为什么<$ c选择了$ c> std :: signed_integral 而不是 std :: integral ?标准中是否定义了任何规则,当有多个概念适合模板参数时选择了哪种模板专业化?

Okay, that's legal, fair enough, but why was std::signed_integral chosen instead of std::integral? Is there any rules defined in the standard with what template specialization gets chosen when multiple concepts qualify for the template argument?

推荐答案

因为概念可以比其他概念更专业,所以有点像模板如何对其进行排序。这称为约束的部分排序

This is because concepts can be more specialized than others, a bit like how template order themselves. This is called partial ordering of constraints

在概念的情况下,当它们包含等效约束时,它们会彼此包含。例如,以下是 std :: integral std :: signed_integral 的实现方式:

In the case of concepts, they subsumes each other when they include equivalent constraints. For example, here's how std::integral and std::signed_integral are implemented:

template<typename T>
concept integral = std::is_integral_v<T>;

template<typename T> //   v--------------v---- Using the contraint defined above
concept signed_integral = std::integral<T> && std::is_signed_v<T>;

对约束进行归一化,编译器将约束表达式简化为:

Normalizing the constraints the compiler boil down the contraint expression to this:

template<typename T>
concept integral = std::is_integral_v<T>;

template<typename T>
concept signed_integral = std::is_integral_v<T> && std::is_signed_v<T>;

在此示例中, signed_integral 表示完全。因此,在某种意义上,带符号的积分更受约束。

In this example, signed_integral implies integral completely. So in a sense, a signed integral is "more constrained" than an integral.

标准这样写:

来自 [temp.func.order] / 2 (强调我的意思):

From [temp.func.order]/2 (emphasis mine):


偏序排序通过依次转换每个模板(请参阅下一段)并使用函数类型执行模板参数推导来选择两个函数模板中的哪个比另一个函数更特殊。
推导过程确定一个模板是否比另一个模板更专业。
如果是这样,则更专业的模板是部分排序过程选择的模板。
如果两个推论都成功,则部分排序将选择约束更严格的模板,如 [temp.constr.order]

Partial ordering selects which of two function templates is more specialized than the other by transforming each template in turn (see next paragraph) and performing template argument deduction using the function type. The deduction process determines whether one of the templates is more specialized than the other. If so, the more specialized template is the one chosen by the partial ordering process. If both deductions succeed, the partial ordering selects the more constrained template as described by the rules in [temp.constr.order].

这意味着如果存在多个可能的替换对于模板,并且两者都是从部分排序中选择的,它将选择受约束最大的模板。

That means that if there is multiple possible substitution for a template and both are choosen from partial ordering, it will select the most constrained template.

来自 [temp.constr.order] / 1


约束对于且仅当对于 P i的析取范式的每个析取子句 P i 时,P包含一个约束 Q P P i 将每个结语 Q j 包含为的合取范式> Q ,其中


  • 析取子句 P i 包含一个连词 Q j 仅在 P i 中存在原子约束 P ia 的情况下 Q j 中的> Q jb ,使得 P ia 包含在内 Q jb

  • a disjunctive clause Pi subsumes a conjunctive clause Qj if and only if there exists an atomic constraint Pia in Pi for which there exists an atomic constraint Qjb in Qj such that Pia subsumes Qjb, and

原子约束 A >当且仅当 A B 使用 B eel.is/c++draft/temp.constr.atomic rel = noreferrer> [temp.constr.atomic]

an atomic constraint A subsumes another atomic constraint B if and only if A and B are identical using the rules described in [temp.constr.atomic].

这描述了编译器用来对约束进行排序并因此对概念进行排序的包含算法。

This describe the subsumption algorithm that compiler use to order constraints, and therefore concepts.

这篇关于C ++ 20概念:当template参数符合多个概念时,会选择哪种模板专业化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆