2

There is a template class A with template parameter T. I want this class to have a method f if T is of integral types. The class A also has a lot of other methods, so I don't want to have specialization of overall A. I understand that this problem can be solved using inheritance, but my question is about concepts and requirements.

This code

 template <typename T>
 struct A {
 void f();
 };
 template <>
 void A<int>::f() {}

works as I expect. It makes implementation of f for the int type only. If I try to call A<std::string>{}.f(); it generates a linker error as expected. But if I write

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

either

 template <typename T> requires std::is_integral_v<T>
 void A<T>::f() {}

the method f is generated for all types, so calling A<std::string>{}.f(); does not give any error.


Also this works

 template <typename T>
 struct A {
 void f() {}
 };
 template <>
 void A<std::string>::f() = delete;

but this

 template <typename T>
 struct A {
 void f() {}
 };
 template <std::integral T>
 struct A<T>::f() = delete;

gives compilation error, namely redefinition of f.


P.S. It seems such constructions are not allowed at all, but g++ just ignores concepts in definition of method f.

Nicol Bolas
482k66 gold badges864 silver badges1.1k bronze badges
asked Oct 15, 2021 at 16:45
1
  • Neither clang nor MSVC can compile your second example. Commented Oct 15, 2021 at 17:14

2 Answers 2

2

There are four syntactical methods of applying constraints to a function.

  1. Type constraint in a template parameter list; template< Concept TypeID >.
  2. Requires clause after a template parameter list; template< class TypeID > requires constexpr-andor-requires-expression.
  3. Constraint on auto in an abbriviated function template; void f(Concept auto id);.
  4. Requires clause after a function declaration; template< class TypeID > void f() requires constexpr-andor-requires-expression.

The function you want to constrain doesn't have a template parameter list so you can't use methods 1 and 2. Method 3 essentially generates template parameters. So that leaves method 4.

#include <concepts>
template< class T >
struct A {
 void f() { /* do something */ }
 void g() requires std::integral<T> { /* do something */ }
 void h() requires std::integral<T>;
 template< std::integral U = T >
 void i() { /* do something */ }
};
template< class T >
void A<T>::h() requires std::integral<T> { /* do something */ }
int main() {
 A<double> dblA;
 dblA.f();
 // dblA.g(); // A<double>::g() is not declared or defined
 // dblA.h(); // A<double>::h() is not declared or defined
 // dblA.i(); // A<double>::h<double>() is not declared or defined
 dblA.i<int>(); // A<double>::h<int>() is declared and defined
 A<int> intA;
 intA.f();
 intA.g(); // A<int>::g() is declared and defined
 intA.h(); // A<int>::h() is declared and defined
 intA.i(); // A<int>::h<int>() is declared and defined
 //intA.i<double>(); // A<int>::h<double>() is not declared or defined
 return 0;
}
answered Dec 8, 2021 at 22:28
Sign up to request clarification or add additional context in comments.

Comments

0

You have to add a new template parameter, which will default to T and to which you can add your constraint of std::integral<>. This compiled with gcc10.3.0 and clang12.0.0, other versions you will have to test yourself.

The code:

#include <concepts>
#include <string>
template <typename T>
struct A
{
 template <typename U = T>
 requires std::integral<U>
 void f();
};
template <typename T>
template <typename U>
requires std::integral<U>
void A<T>::f()
{
}
int main()
{
 A<int> a;
 a.f();
 A<std::string> s; // This works
 // s.f(); // Compilation error: constraint not satisfied
 return 0;
}
answered Oct 15, 2021 at 18:06

1 Comment

I don't believe this works in the way the OP wants. Try A<std::string>().f<int>(); which will compile just fine.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.