0

I am trying to create template class for arbitrary precision unsigned integer type. In order to do this properly I need to have multiple versions of this template class with different constraints. Here is my version:

template<uint32_t N,bool Destroy=true,bool Const=false>
    requires(N >= 16 and __globals::is_power_2(N) and Destroy and not Const)
class _uint;

template<uint32_t N,bool Destroy,bool Const>
    requires(N >= 16 and __globals::is_power_2(N) and not Destroy and Const)
class _uint;

/* Some necessary declarations */

template <uint32_t N, bool Destroy, bool Const>
    requires (N >= 16 && __globals::is_power_2(N) && Destroy && not Const)
class _uint
{
    // ... Class definition ...
};

template <uint32_t N, bool Destroy, bool Const>
    requires (N >= 16 && __globals::is_power_2(N) && not Destroy && Const)
class _uint
{
    // ... Class definition ...
};

Unfortunately, compiler tells me the following:

error: redeclaration of ‘template<unsigned int N, bool Destroy, bool Const> requires N >= 16 && is_power_2(std::size_t)(N) && Destroy && !Const class _uint’ with different constraints

I don't understand why I can't do this. My vision was that 'requires' statement is like a strict hint for a compiler that dictates which version of the class it should compile. So it shouldn't be bothered about how many declarations of the same class I have until it actually find a conflict, for example when two constraints satisfy one set of template arguments. Can someone explain me this, please?

I want not only to find out a work around but also why I need to do this. In referenced duplicate person doesn't explain why I need to use partial specialization in order to fix this. For me it still remains bizarre..

  • 2
    This doesn't address the question, but names that contain two consecutive underscores (`__globals`) and names that begin with an underscore followed by a capital letter are reserved for use by the implementation. Don't use them in your code. – Pete Becker Aug 13 '23 at 11:47
  • How your compiler should notice any difference between ```template requires(N >= 16 and __globals::is_power_2(N) and Destroy and not Const) class _uint;``` and ```template requires (N >= 16 && __globals::is_power_2(N) && Destroy && not Const) class _uint { // ... Class definition ... };``` ? look at [this](https://en.cppreference.com/w/cpp/keyword/and) – Iman Abdollahzadeh Aug 13 '23 at 11:48
  • @ImanAbdollahzadeh This is not about using `and` and `&&`. – Nelfeal Aug 13 '23 at 11:49
  • @Nelfeal Then it is just the declaration of a template class ```_uint``` and a similar instantiation. – Iman Abdollahzadeh Aug 13 '23 at 11:52
  • 1
    @Jarod42 Why would you delete my comment by closing this as duplicate? I specifically did not vote to close because OP asks "Can someone explain me this", which sounds like a question about the standard, not about how to deal with the compiler error. And it is now obvious since OP added the language-lawyer tag as I suggested. The duplicate does not answer this question. – Nelfeal Aug 13 '23 at 11:56
  • You need to use specialisations because you can't have two classes with the same name. You need to declare that you have a templated class then specialise that class with different sets of restrictions. Without the initial declaration the compiler thinks you're trying to declare the same class twice which isn't allowed – Alan Birtles Aug 13 '23 at 15:02
  • The language is extended to replace old syntactic atrocities like SFINAE for e.g. or to add new capabilities like multidimensional operator [] in C++23. The purpose is not to replace well established solutions (template specialization in this case) with "nicer" ones because if that would be done, the language would become even more complicated than it is already. – Patrick Fromberg Aug 13 '23 at 15:09
  • The `language-lawyer` tag looks a bit weird here. "You can't have more than one class (or class template) with the same name" is something basic, does it really need a standard reference? – HolyBlackCat Aug 14 '23 at 08:34

1 Answers1

0

TL;DR: Class templates cannot be overloaded. All declarations of the same class template must agree with each other.

This is just how the language is designed. If you want to change that, write a proposal.

[basic.link]/11:

For any two declarations of an entity E:

  • If one declares E to be a class template, the other shall do so with the same kind and an equivalent template-head ([temp.over.link]).

[temp.over.link]/6:

Two template-heads are equivalent if [...] and if either template-head has a requires-clause, they both have requires-clauses and the corresponding constraint-expressions are equivalent.

[temp.over.link]/5:

Two expressions involving template parameters are considered equivalent if two function definitions containing the expressions would satisfy the one-definition rule, except that the tokens used to name the template parameters may differ as long as a token used to name a template parameter in one expression is replaced by another token that names the same template parameter in the other expression.

cpplearner
  • 13,776
  • 2
  • 47
  • 72