Tuesday Coding Tip 02 - Template with type-specific API

posted Originally published at medium.com 1 min read

Tuesday coding tips are super short posts about various tidbits mainly from C++, but also from other programming languages I use. You can also follow the #TuesdayCodingTips hashtag on Mastodon and Linkedin.


What if you had a template class and you wanted to give it extra methods for certain specializations?

For example, you might want to make a templated initialization guard and you want it to be as non-intrusive as possible. So you want it to support arithmetic operations if the underlying type is an arithmetic type.

Before C++20, you could leverage std::enable_if. However, such code is clunky and unreadable:

#include <type_traits>
#include <string>

// Pre C++20
template<class T>
class TemplatedClass
{
public:
  template<class = typename std::enable_if<std::is_integral<T>::value>::type>
  void foo() {}
};

int main()
{
  TemplatedClass<int> a;
  a.foo(); // OK

  TemplatedClass<std::string> b;
  b.foo(); /* Error:
  error: failed requirement 'std::is_integral<std::basic_string...>' requested here
  error: no matching member function for call to 'foo'
  note: candidate template ignored: couldn't infer template argument ''
  */
}

With C++20, you can use concepts and the requires keyword to clean up the syntax significantly, either by in-place definition of type properties or by defining a dedicated concept. It also improves readability of error messages.

#include <type_traits>
#include <string>

// C++20, requires
template<class T>
class TemplatedClass2
{
public:
  template<typename = void>
  requires std::is_integral_v<T>
  void foo() {}
};

// C++20 with concept
template<class T>
concept IsIntegral = std::is_integral_v<T>;

template<class T>
class TemplatedClass3
{
public:
  template<typename = void>
  requires IsIntegral<T>
  void foo() {}
};

int main() {
  TemplatedClass2<int> a;
  a.foo(); // Ok

  TemplatedClass3<std::string> b;
  b.foo(); /* Error:
  error: no matching member function for call to 'foo'
  note: candidate template ignored: constraints not satisfied [with $0 = void]
  note: because 'std::basic_string<char>' does not satisfy 'IsIntegral'
  note: because 'std::is_integral_v<std::basic_string<char> >' evaluated to false
  */
}

More Posts

Tuesday Coding Tip 06 - Explicit template instantiation

Jakub Neruda - Apr 7

Tuesday Coding Tip 05 - Object initialization in C++

Jakub Neruda - Mar 31

Your Tech Stack Isn’t Your Ceiling. Your Story Is

Karol Modelski - Apr 9

I’m a Senior Dev and I’ve Forgotten How to Think Without a Prompt

Karol Modelski - Mar 19

Tuesday Coding Tip 04 - Precompiled headers

Jakub Neruda - Mar 24
chevron_left

Related Jobs

View all jobs →

Commenters (This Week)

14 comments
7 comments
4 comments

Contribute meaningful comments to climb the leaderboard and earn badges!