Inconsistent behavior between gcc and clang when c++20 concepts are involved

Viewed 87

Does anybody know about inconsistency below? where gcc and clang behaving differently when c++20 concepts are involved.

Basically declared concept in gcc is able to find my custom operator== even through it is declared after the concept, but it isn't the case for plain functions( with user defined names ). Whereas the concept in clang in both cases aren't able to find any of my declarations unless they are declared before the concept.

And the main question is: "Which compiler has correct behavior?"

NOTE THAT: both compilers are working fine if all of my declarations declared before a concept.

  • Output: /// gcc-10.2 and gcc-11

    EqComparable=1
    Comparable=0
    
  • Output: /// clang-11 and clang-12

    EqComparable=0
    Comparable=0
    
#include <iostream>
#include <cstdlib>
#include <string>
#include <regex>

template< typename T1, typename T2 >
concept EqualityComparable = requires( T1 t1, T2 t2 ) { t1 == t2; };

template< typename T1, typename T2 >
concept Comparable = requires( T1 t1, T2 t2 ) { compare(t1,t2); };

std::string operator==( const std::string&, const std::regex& )
{
    return {"hello"};
}

std::string compare( const std::string&, const std::regex& )
{
    return {"hello"};
}

int main()
{    
    std::cout << "EqComparable=" << EqualityComparable<std::string, std::regex> << std::endl;
    std::cout << "Comparable=" << Comparable< std::string, std::regex > << std::endl;
}
1 Answers

Clang is correct. gcc just has issues with lookup for operators.

In both of your concepts, we are doing lookup for a name: operator== in one case and compare in the other. We first do regular unqualified lookup and then do argument-dependent lookup.

In both cases, both lookups should find nothing: there are no viable candidates found by unqualified lookup (nothing declared before the concepts that unqualified lookup could find) and no viable candidates found by ADL (we only look in the associated namespaces, which would be std, but your candidates are not in std, they are in the global namespace: ::). Having no candidates, both concept checks should fail.

However, gcc just finds your operator== anyway. It shouldn't though, that's incorrect.

This is why:

NOTE THAT: both compilers are working fine if all of my declarations declared before a concept.

Because now regular unqualified lookup finds the candidates in question.

Related