3
template<classT>
class MyClass {
using KeyType = int;
using MapType = std::map<KeyType, int64_t>;
MapType map_;

template <class T1 = T, class = std::enable_if_t<std::is_same<T1, int>{}>>
  IndexValueType LowerBound(KeyType k) const {
    auto it = map_.lower_bound(k);
    if (it == map_.end()) {
      return NOT_FOUND;
    }
    return it->second;
  }
};

What does these 2 assignments do in this context?

  • class T1 = T
  • class = std::enable_if_t<std::is_same<T1, int>{}>
康桓瑋
  • 33,481
  • 5
  • 40
  • 90
Huy Le
  • 1,439
  • 4
  • 19
  • Ah I've edited the question. So in this case "T1 = T" just means T1 has the same class as T right? But then what's the point of this assignment? – Huy Le Feb 09 '22 at 04:20
  • 1
    From what you are showing it doesn't make much sense to me. There is probably more context missing. The template parameters make it so that `LowerBound` can only be called if `T` is `int` or `int` is given explicitly as template argument. – user17732522 Feb 09 '22 at 04:22
  • So using template{}>> should have the same effect (enable LowerBound if T is int) right? – Huy Le Feb 09 '22 at 04:25
  • 1
    No, `T1` is required to make SFINAE work. There is surely a duplicate for this somewhere if that is your question. – user17732522 Feb 09 '22 at 04:29
  • Ah okay so the keyword is SFINAE. – Huy Le Feb 09 '22 at 04:32
  • 1
    If your question is just what `enable_if` does, see https://stackoverflow.com/questions/25284499/how-does-stdenable-if-work. For my previous comment see https://stackoverflow.com/questions/6972368/stdenable-if-to-conditionally-compile-a-member-function. Also for `enable_if_t` specifically, see https://stackoverflow.com/questions/62319649/what-is-the-difference-between-stdenable-if-and-stdenable-if-t – user17732522 Feb 09 '22 at 04:48

1 Answers1

2

LowerBound is a member template function declared inside the class template MyClass. It's similar to a function template but it is enclosed in a class (template).

The code can be simplified as

template <typename T>
class MyClass {

    template <typename T1 = T, typename = std::enable_if_t<std::is_same<T1, int>{}>>
    IndexValueType LowerBound(KeyType k) const {}
};

The first assignment T1 = T means the default argument for the first template parameter is the same type of T. If you are not explicitly specified, T1 will be T. You could of course explicitly specify other types.

The second assignment here is an usage of std::enable_if. Also pointed in the comments, it's a simple way to apply SFINAE. Here it will disable(ignore) templates when T1 is not the same as int. Since the second parameter is only to restrict the first parameter and has no usage in the definition, its name is ignored.

MyClass<int> mc1; // T is int
mc1.LowerBound(...) // T1 is int, when not specified explicitly
mc1.LowerBound<std::int32_t>(...) // T1 is std::int32_t here
MyClass<double> mc2; // T is double
mc2.LowerBound<int>(...) // OK, T1 is int 
mc2.LowerBound(...) // T1 is substitued with double here and will cause compile error since is not int
LWimsey
  • 6,189
  • 2
  • 25
  • 53
Nimrod
  • 2,908
  • 9
  • 20