1

This is just a minimal reproducible example:

import <unordered_set>;
import <functional>;

template<class c>
class my_class {
};

template<class c>
struct std::hash<my_class<c>> {
    std::size_t operator()(my_class<c> const &s) const noexcept {
        return 0;
    }
};


int main() {
    std::unordered_set<my_class<char>> x;
}

This code, when compiled with g++ -std=c++20 -fmodules-ts test.cpp produces this error:

C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\SOURAV~1\AppData\Local\Temp\cclOkCUA.o:test.cpp:(.text$_ZNSt16allocator_traitsISaIPNSt8__detail15_Hash_node_baseEEE10deallocateERS3_PS2_y[_ZNSt16allocator_traitsISaIPNSt8__detail15_Hash_node_baseEEE10deallocateERS3_PS2_y]+0x2d): undefined reference to `std::is_constant_evaluated()'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\SOURAV~1\AppData\Local\Temp\cclOkCUA.o:test.cpp:(.text$_ZNSt16allocator_traitsISaINSt8__detail10_Hash_nodeI8my_classIcELb0EEEEE10deallocateERS5_PS4_y[_ZNSt16allocator_traitsISaINSt8__detail10_Hash_nodeI8my_classIcELb0EEEEE10deallocateERS5_PS4_y]+0x2d): undefined reference to `std::is_constant_evaluated()'
collect2.exe: error: ld returned 1 exit status

Instead if I define template argument directly in hash struct, there is no error!

template<>
struct std::hash<my_class<char>> {
    std::size_t operator()(my_class<char> const &s) const noexcept {
        return 0;
    }
};

I am confused what is the error!

Sourav Kannantha B
  • 2,860
  • 1
  • 11
  • 35
  • I'm not sure it is is legal to add partial specializations – NathanOliver May 26 '22 at 12:10
  • @NathanOliver [this](https://en.cppreference.com/w/cpp/language/partial_specialization) site says partial specialization is allowed! – Sourav Kannantha B May 26 '22 at 12:36
  • 1
    They are allowed in the language, but I'm not sure if you are allowed to partially specialize templates defined in `std::`. [this](https://en.cppreference.com/w/cpp/language/extending_std#:~:text=Adding%20template%20specializations-,Class%20templates,where%20such%20specializations%20are%20prohibited.) only says *It is allowed to add template specializations for any standard library class template to the namespace std only if the declaration depends on at least one program-defined type and the specialization satisfies all requirements for the original template*. – NathanOliver May 26 '22 at 12:37
  • Not sure if that covers partial specialization or not. – NathanOliver May 26 '22 at 12:38
  • @NathanOliver then isn't it possible to write a `std::hash` for any instantiation of `my_class`? Something like `std::hash>`? – Sourav Kannantha B May 26 '22 at 12:43
  • I don't think it is, but like I said I'm not sure. I've never done it and never seen it done but that doesn't really mean anything. The thing is that `template_name` and `template_name` could resolve to two completely different types, which could require completely different hashing techniques. – NathanOliver May 26 '22 at 12:46
  • @NathanOliver if I have a unique member variable `id` in `my_class`, then I can just return it in `std::hash` regardless of particular instantiation. – Sourav Kannantha B May 26 '22 at 13:16
  • The partial specialization is just fine, and the error is close to nonsensical; but the fact that the problem manifests as a linker error is helpful as it strongly implies the issue is related to modules. I'd wager if you switch from `import` to `#include` that everything works just fine – the unsurprising _actual_ problem is simple incomplete modules support. – ildjarn May 26 '22 at 16:32
  • @ildjarn I tried running the same program, just by replacing `import` by `#include`. But the problem still exists. – Sourav Kannantha B May 27 '22 at 04:56
  • @ildjarn But interestingly, if I do the above step, and also remove `-fmodules-ts` then program works just fine. – Sourav Kannantha B May 27 '22 at 04:58
  • @ildjarn since it was a linker error, I tried to define the function myself, which gave me redefinition error. Later, I resolved the problem by just declaring the function - adding this line to source code resolved the problem `constexpr bool std::is_constant_evaluated() noexcept;` – Sourav Kannantha B May 27 '22 at 05:03
  • Declaring or defining an stdlib entity is forbidden by the standard, and in any case `std::is_constant_evaluated` is entirely compiler magic so there is no possible way to write it in plain C++(20) and have it function correctly. The only correct solution is to avoid using modules until the implementation is actually functional. – ildjarn May 27 '22 at 11:55

1 Answers1

0

I think it is just some bug in GCC modules implementation as suggested by @ildjarn in comments.

I was able to get rid of error by adding this line in the source code:
constexpr bool std::is_constant_evaluated() noexcept;

But I'm not sure what exactly was wrong or why did adding this solved the error.

Sourav Kannantha B
  • 2,860
  • 1
  • 11
  • 35