1

I want to specialize a method of a class X for floating point types. The following code compiles and works perfectly:

x.hpp:

template <typename T>
class X {
 public:
  ...
  T bucket_width(const BucketID index) const;
  T bucket_min(const BucketID index) const;
  T bucket_max(const BucketID index) const
  ...
};

x.cpp:

...

template <typename T>
T X<T>::bucket_width(const BucketID index) const {
  return bucket_max(index) - bucket_min(index) + 1;
};

template <>
float X<float>::bucket_width(const BucketID index) const {
  return bucket_max(index) - bucket_min(index);
};

template <>
double X<double>::bucket_width(const BucketID index) const {
  return bucket_max(index) - bucket_min(index);
};

...

Now, similarly to this answer I changed the cpp file to:

template <typename T>
T X<T>::bucket_width(const BucketID index) const {
  return bucket_max(index) - bucket_min(index) + 1;
};

template <typename T>
std::enable_if_t<std::is_floating_point_v<T>, T> X<T>::bucket_width(const BucketID index) const {
  return bucket_max(index) - bucket_min(index);
};

Unfortunately, this results in the following compiler error:

.../x.cpp:46:56: error: return type of out-of-line definition of 'X::bucket_width' differs from that in the declaration
std::enable_if_t<std::is_floating_point_v<T>, T> X<T>::bucket_width(const BucketID index) const {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                       ^

Can someone explain to me what I am missing?
Thanks in advance!

Edit: We explicitly instantiate the template classes at the end of the cpp file so that we can do template code in the cpp file.

Tim Zimmermann
  • 6,132
  • 3
  • 30
  • 36
  • 1
    You should not be splitting a template in a header and cpp file: https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file – NathanOliver May 24 '18 at 16:05
  • The error message looks like your declaration of X::bucket_width does not contain the enable_if part you added in the definition. – Ron Kluth May 24 '18 at 16:11
  • @RonKluth How do I add the enable_if part correctly to the declaration? – Tim Zimmermann May 24 '18 at 16:17

1 Answers1

7

Can someone explain to me what I am missing?

The error explains it:

.../x.cpp:46:56: error: return type of out-of-line definition of 'X::bucket_width' differs from that in the declaration

That is, the function is declared to return a T but you're defining it to return a std::enable_if_t<std::is_floating_point_v<T>, T>. Those don't match and need to.

More generally, what you're trying to do is to partially specialize a function template, which isn't possible.

A simple solution here is to use if constexpr:

template <typename T>
T X<T>::bucket_width(const BucketID index) const {
  if constexpr (std::is_floating_point_v<T>) {
    return bucket_max(index) - bucket_min(index);
  } else {
    return bucket_max(index) - bucket_min(index) + 1;
  }
};
Barry
  • 286,269
  • 29
  • 621
  • 977