基于具有相关参数的概念的重载解决方案

Wut*_*utz 5 c++ language-lawyer overload-resolution c++-concepts c++20

我正在尝试使用概念来重载其参数取决于模板参数的模板化函数。不幸的是,这在 gcc 上失败了,报告了一个不明确的过载。

在我的项目中,我的代码在 gcc 9.3 中编译,但在 gcc 12.2 中失败。但在尝试最小化代码时,我最终得到了这个,这在两个 gcc 版本上都失败了,但在 clang 15.0.0 中有效:

#include <type_traits>
#include <iostream>

struct A
{
    using value_type = int;
};
struct B
{
    using value_type = int;
};

template<typename Candidate>
concept something = requires {
    typename Candidate::value_type;
};
template<typename Candidate>
concept something_specific = something<Candidate> && std::is_same_v<Candidate, A>;

template<something T>
void foo()
{
    std::cout << "Something" << std::endl;
}
template<something_specific T>
void foo()
{
    std::cout << "Something specific" << std::endl;
}

template<something T>
void bar(const typename T::value_type& s)
{
    std::cout << "Something: " << s << std::endl;
}
template<something_specific T>
void bar(const typename T::value_type& s)
{
    std::cout << "Something specific: " << s << std::endl;
}

int main()
{
    foo<B>(); // works
    foo<A>(); // works

    bar<B>(1); // works
    bar<A>(2); // ambiguous overload

    return 0;
}

Run Code Online (Sandbox Code Playgroud)

查看godbolt,错误信息如预期:

<source>:48:11: error: call of overloaded 'bar<A>(int)' is ambiguous
   48 |     bar<A>(2); // ambiguous overload
      |     ~~~~~~^~~
<source>:32:6: note: candidate: 'void bar(const typename T::value_type&) [with T = A; typename T::value_type = int]'
   32 | void bar(const typename T::value_type& s)
      |      ^~~
<source>:37:6: note: candidate: 'void bar(const typename T::value_type&) [with T = A; typename T::value_type = int]'
   37 | void bar(const typename T::value_type& s)
      |      ^~~
Run Code Online (Sandbox Code Playgroud)

我期望something_specific选择重载,因为限制模板参数的概念更加具体。我们可以看到这foo已经是正确的,否则它也会含糊不清。

当然,我可以让它与一个requires子句一起工作,但我希望它按原样工作。所以我想了解这是否不受支持或者是否是编译器问题。clang 编译这段代码是否正确?