I've the following simple c++20 test:
#include <type_traits>
/////////////////////////////////////// constraints
template <typename Type> concept isConst = ::std::is_const_v<Type>;
template <typename Type> concept isNotConst = !isConst<Type>;
/////////////////////////////////////// class decleration
template <typename T>
class TestRef;
template <isNotConst T>
struct TestRef<T> {
explicit TestRef(T& value) noexcept;
};
template <isConst T>
struct TestRef<T> {
explicit TestRef(T& value) noexcept;
};
/////////////////////////////////////// class implementation
template <isNotConst T>
TestRef<T>::TestRef(T& value) noexcept {}
template <isConst T>
TestRef<T>::TestRef(T& value) noexcept {}
/////////////////////////////////////// main
int main()
{
int a{ 1 };
TestRef<int> ref1{ a };
TestRef<const int> ref2{ a };
return 0;
}
This exemple compiles fine with g++ 12.2.0. However, using clang++ 14.0.6, it does not. Here is the error:
error: incomplete type 'TestRef' named in nested name specifier
I failed to identify the reason why it does and how to work around it.
What I understood is that it does not choose the specialized structure. It uses the basic one that is not defined.
If I do define it, I get the error:
error: type constraint differs in template redeclaration
What can I do to fix the issue?
If there's no reason that you must use concepts, you can use a pre-C++20 way to implement it.
template <typename T, typename = void>
class TestRef;
template <typename T>
struct TestRef<T, std::enable_if_t<std::is_const_v<T>>> {
explicit TestRef(T& value) noexcept;
};
template <typename T>
struct TestRef<T, std::enable_if_t<!std::is_const_v<T>>> {
explicit TestRef(T& value) noexcept;
};
/////////////////////////////////////// class implementation
template <typename T>
TestRef<T, std::enable_if_t<std::is_const_v<T>>>::TestRef(T& value) noexcept {}
template <typename T>
TestRef<T, std::enable_if_t<!std::is_const_v<T>>>::TestRef(T& value) noexcept {}
I'm showing you a general way. In your case, you don't have another specialization for the non-const version. You can fill them in the primary template.