2

I want to specialize a member function of a class template as follows:

#include <concepts>

template <typename T>
struct S {
    void f();
};

template <typename T>
void S<T>::f() {
}

// (0) This is fine.
template <>
void S<int>::f() {
}

// (1) This triggers an error.
template <std::integral T>
void S<T>::f() {
}

The specialization (0) is fine, but specializes f() only for the int type. Instead, I would like to specialize it, e.g., for any integral type, as in (1). Is this possible using C++20 concepts? Notice that std::integral is just an example and that my specific case makes use of user-defined concepts.

fdev
  • 127
  • 12
  • Does this answer your question? [Template specialization of particular members?](https://stackoverflow.com/questions/1501357/template-specialization-of-particular-members) – Artyer Feb 07 '22 at 21:52
  • 4
    You cannot partially specialize member functions. You can instead in the base template do `if constexpr (std::integral)`. – Artyer Feb 07 '22 at 21:52
  • @Artyer the question you linked is different since I aim at *fully* (not partially) specializing a member function of a class template for a whole range of types (i.e., all `std::integral` types). Also, unfortunately I cannot do what I want using `if constexpr` because the main implementation of `f()` already exists and is provided externally! – fdev Feb 07 '22 at 22:09
  • @fdev The types that satisfy a concept are generally not bounded, so there can't really be a syntax for explicit specialization for every type satisfying the concept. In the case of `std::integral`, absent implementation-defined types, there is a fixed list of types, which you could explicitly specialize on, one-by-one, maybe with the help of a macro. – user17732522 Feb 07 '22 at 22:22
  • 3
    `template void S::f()` should be a partial specialization in the same way that `template void S::f()` would be: You would need a partial specialization of `S` for that to refer to, i.e., `template struct S { void f(); }` – Artyer Feb 07 '22 at 22:37
  • I see, so there is no way around my issue? That is, if I want to specialize `f()` I must necessarily specialize the whole struct `S` with all its member functions, no matter how many, right? This sounds troublesome, but if you confirm that there is no other way, even better by backing it up with some references, I will accept your answer! – fdev Feb 08 '22 at 08:30

1 Answers1

2

Simply use a trailing requires-clause. The compiler will choose the most constrained function:

#include <concepts>
#include <iostream>

template <typename T>
struct S {
    void f();
    
    void f() requires std::integral<T>;
};

template <typename T>
void S<T>::f() {
  std::cout << "general\n";
}

template <typename T>
void S<T>::f() requires std::integral<T> {
  std::cout << "constrained\n";
};


int main() {
  S<int> x;
  S<double> y;
  
  x.f(); // prints constrained
  y.f(); // prints general

  return 0;
}
metalfox
  • 6,301
  • 1
  • 21
  • 43
  • As I stated in a comment to the main question, unfortunately I cannot modify the declaration of `S` because it is externally provided! Although I can redefine it for individual types (e.g., `int`), it seems like I cannot do it for classes of types (e.g., `std::integral`). Do you also confirm this point? – fdev Feb 08 '22 at 13:17
  • 1
    @fdev: Then you should write a partial specialization of `S` as @Artyer mentioned in their comment: https://wandbox.org/permlink/UekSTTfRgYp2UydA – metalfox Feb 08 '22 at 14:37
  • Yes, but again this is undesirable because the `S` struct may contain (and in my specific case it does contain) many member functions, and I only need to specialize one. – fdev Feb 08 '22 at 15:03
  • 1
    @fdev: In that case you could inherit from `S` and partially specialise the derived class: https://wandbox.org/permlink/xeYWHbg34hSVd2Nc – metalfox Feb 08 '22 at 15:17
  • This looks like the only way, but it is still not what I am looking for because I think it could cause troublesome bugs where I think I am using the constrained `f()`, but in fact I am using the base class version. Nonetheless, thank you very much for your help! – fdev Feb 08 '22 at 15:46