admin管理员组

文章数量:1313752

I've been playing around with C++20 concepts and ran into an issue with my GCC 9.4 compiler, which I ultimately want to support. I created this minimal reproducible example to showcase the problem:

#include <iostream>
#include <type_traits>

template <typename T, typename Type>
concept IsSame = std::is_same_v<T, Type>;

template <typename Scalar>
class MyClass {
   public:
    template <typename T>
    using ScalarT = T;

    template <typename T>
    requires IsSame<T, typename MyClass<Scalar>::template ScalarT<double>>
    static void print(const T& b);
};

// Compilation depends on compiler
template<typename Scalar>
template<typename T>
requires IsSame<T, typename MyClass<Scalar>::template ScalarT<double>>
void MyClass<Scalar>::print(const T& t) {
    std::cout << std::fixed << t << " as Scalar is " << std::fixed << static_cast<Scalar>(t) << std::endl;
}

int main() {
    MyClass<int>::print(6.0);
    return 0;
}

GCC 9.4 (with -std=c++2a -fconcepts) and the more recent GCC 14.2 (with -std=c++20) complain that:

<source>:334:6: error: no declaration matches 'void MyClass<Scalar>::print(const B&)'
  334 | void MyClass<Scalar>::print(const B& b) {
      |      ^~~~~~~~~~~~~~~
<source>:327:17: note: candidate is: 'template<class Scalar> template<class T>  requires  IsSame<T, double> static void MyClass<Scalar>::print(const T&)'
  327 |     static void print(const T& b);
      |                 ^~~~~
<source>:320:7: note: 'class MyClass<Scalar>' defined here
  320 | class MyClass {

However, both GCC compilers are ok with defining the function inline, as:

    template <typename T>
    requires IsSame<T, typename MyClass<Scalar>::template ScalarT<double>>
    static void print(const T& t) {
        std::cout << std::fixed << t << " as Scalar is " << std::fixed << static_cast<Scalar>(t) << std::endl;
    }

or

    template <typename T>
    requires IsSame<T, ScalarT<double>>
    static void print(const T& t) {
        std::cout << std::fixed << t << " as Scalar is " << std::fixed << static_cast<Scalar>(t) << std::endl;
    }

Clang 19.1 (with -std=c++2a) has no issue, and prints 6.000000 as Scalar is 6.

I know I could also do the following:

template <IsSame<ScalarT<double>> T>
    static void print(const T& t) {
        std::cout << std::fixed << t << " as Scalar is " << std::fixed << static_cast<Scalar>(t) << std::endl;
    }

But this has the same issue with GCC, where moving the implementation outside the class does not work:

template<typename Scalar>
template<IsSame<typename MyClass<Scalar>::template ScalarT<double>> T>
static void MyClass<Scalar>::print(const T& t) {
    std::cout << std::fixed << t << " as Scalar is " << std::fixed << static_cast<Scalar>(t) << std::endl;
}

本文标签: GCC stricter than Clang for resolving dependent names for conceptsStack Overflow