Home > OS >  Clang partial class template specialization error
Clang partial class template specialization error

Time:09-06

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?

CodePudding user response:

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 {}

Demo

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.

CodePudding user response:

I failed to identify the reason why it does

GCC is correct in accepting the given code as the program is well-formed. Here is a similar clang bug report.

What can I do to fix the issue?

Since clang and msvc are wrong in rejecting the code here, the simplest way to make the program work with all compilers is to simply provide the definitions for the constructors inside the class template as shown below:


template <isNotConst T>
struct TestRef<T> {
    //implement inside instead of out of class definition
    explicit TestRef(T& value) noexcept
    {

    }
};

template <isConst T>
struct TestRef<T> {
    //implement inside instead of out of class definition
    explicit TestRef(T& value) noexcept
    {

    }
};

Working demo

  • Related