c++ - 概念的部分排序如何解决约束重载?

标签 c++ templates concept

根据 cppreference ,约束对包含的部分排序用于确定“模板模板参数的最佳匹配”。在示例部分中,选择了“更受约束”的选项,即更强/更紧的条件。但在实践中,当函数概念约束明确排序并且特定调用可以清楚地区分最强选项时,我发现了一些令人困惑的行为。
我正在 gcc 版本 10.2.0 (Homebrew GCC 10.2.0) 上测试以下内容: 使用:

template <typename... Ts>
void foo (Ts... ts) // option 1
{
    (cout << ... << ts) << endl;
}

template <typename... Ts> requires (sizeof...(Ts)<=3)
void foo (Ts... ts) // option 2
{
    (cout << ... << ts) << endl;
}
调用foo(1,2)将选择选项 2,因为它的约束明显强于选项 1。另一方面,这显然会导致歧义:
template <typename... Ts>
void foo (Ts... ts) // option 1
{
    (cout << ... << ts) << endl;
}

template <typename... Ts> requires (sizeof...(Ts)<=3)
void foo (Ts... ts) // option 2
{
    (cout << ... << ts) << endl;
}

template <typename... Ts> requires (same_as<Ts, int> && ...)
void foo (Ts... ts) // option 3
{
    (cout << ... << ts) << endl;
}
自从打了 foo(1,2)无法决定是选择选项 2 还是选项 3,因为它们无法比较。现在,如果我理解正确,可以添加一个连词,例如:
template <typename... Ts>
void foo (Ts... ts) // option 1
{
    (cout << ... << ts) << endl;
}

template <typename... Ts> requires (sizeof...(Ts)<=3)
void foo (Ts... ts) // option 2
{
    (cout << ... << ts) << endl;
}

template <typename... Ts> requires (same_as<Ts, int> && ...)
void foo (Ts... ts) // option 3
{
    (cout << ... << ts) << endl;
}

template <typename... Ts> requires (sizeof...(Ts)<=3) && (same_as<Ts, int> && ...)
void foo (Ts... ts) // option 4
{
    (cout << ... << ts) << endl;
}
调用foo(1,2)应该使用选项 4 解决,但我的编译器另有说明:
In function 'int main()':
error: call of overloaded 'foo(int, int)' is ambiguous
      |     foo(1,2);
      |            ^
note: candidate: 'void foo(Ts ...) [with Ts = {int, int}]'
      | void foo (Ts... ts) // option 1
      |      ^~~
note: candidate: 'void foo(Ts ...) [with Ts = {int, int}]'
      | void foo (Ts... ts) // option 2
      |      ^~~
note: candidate: 'void foo(Ts ...) [with Ts = {int, int}]'
      | void foo (Ts... ts) // option 3
      |      ^~~
note: candidate: 'void foo(Ts ...) [with Ts = {int, int}]'
      | void foo (Ts... ts) // option 4
这是为什么?如果这是不可避免的,有没有办法解决这个问题?

最佳答案

如果您尝试编译:

template <typename... Ts> requires (sizeof...(Ts)<=3)
void foo (Ts... ts) // option 2
{
    (cout << ... << ts) << endl;
}

template <typename... Ts> requires (sizeof...(Ts)<=3) && (is_same_v<Ts, int> && ...)
void foo (Ts... ts) // option 4
{
    (cout << ... << ts) << endl;
}
clang 12你收到消息:
note: similar constraint expressions not considered equivalent; 
constraint expressions cannot be considered equivalent unless 
they originate from the same concept
使用此提示,您可以将代码重写为:
#include <iostream>
#include <type_traits>

using namespace std;
template <typename... Ts>
void foo (Ts... ts) // option 1
{
    (cout << ... << ts) << endl;
}

template<class ... Ts>
concept LessThan3 =  (sizeof...(Ts)<=3)  ;

template<class ... Ts>
concept AllInt =  (std::same_as<Ts, int> && ...);


template <typename... Ts> requires LessThan3<Ts...>
void foo (Ts... ts) // option 2
{
    (cout << ... << ts) << endl;
}


template <typename... Ts> requires AllInt<Ts...>
void foo (Ts... ts) // option 3
{
    (cout << ... << ts) << endl;
}

template <typename... Ts> requires LessThan3<Ts...> &&  AllInt<Ts...>
void foo (Ts... ts) // option 4
{
    (cout << ... << ts) << endl;
}

int main(){
   
    foo(1,2);
    return 0;
}
使用 gcc 和 clang 编译:demo

关于c++ - 概念的部分排序如何解决约束重载?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64066633/

相关文章:

templates - 如何使用 html-webpack-plugin + twig-loader 包含图像?

c++ - 检查成员函数时 SFINAE 测试失败

progress - 我们如何估计程序完成所需的时间并将其反射(reflect)到进度条上?

c++ - 使用带有 --extract-all 的 xgettextt 处理复数

c++ - 根据另一个字符串创建由空格 (_) 和空格组成的字符串

c++ - 如何引用模板类中定义的typedef

javascript - 从今天起获得先前值(value)的最佳方式

oop - 运行时多态性可以称为控制反转还是其他

c++ - 如何在 C++ 中的不同翻译单元之间共享枚举实例?

c++ - 调用 for 循环条件 (c++)