Search code examples
c++c++11visual-c++constexprenable-if

How to work around "function template has already been defined" when using std::enable_if with constexpr method


When using a constexpr method as the argument of std::enable_if_t, old MSVC compilers complain about "function template has already been defined". G++ and newer MSVC compilers accept that. How I can make that work also with old MSCV compilers?

Example code:

#include <climits>
#include <iostream>
#include <type_traits>

template <typename NumberType>
constexpr auto doBitCountsMatch(const int f_bitCount) -> bool {

  return (static_cast<int>(CHAR_BIT * sizeof(NumberType)) == f_bitCount);
}

template <typename NumberType, int bitCount>
auto test()
    -> std::enable_if_t<doBitCountsMatch<NumberType>(bitCount), NumberType> {
  std::cout << "Bit counts match." << std::endl;

  return 0;
}

template <typename NumberType, int bitCount>
auto test()
    -> std::enable_if_t<!doBitCountsMatch<NumberType>(bitCount), NumberType> {
  std::cout << "Bit counts don't match." << std::endl;

  return 0;
}

int main() {
  int number = 0;

  test<decltype(number), 32>();
  return 0;
}

And here in Compiler Explorer: https://godbolt.org/z/15PnPhvo8: MSVC 19.14 rejects the code, MSVC 19.33 accepts it. Why do the old compilers reject the code?


Solution

  • You might use std::enable_if_t as template parameter instead:

    template <typename NumberType, int bitCount,
              std::enable_if_t<doBitCountsMatch<NumberType>(bitCount), int> = 0>
    auto test() -> NumberType
    {
      std::cout << "Bit counts match." << std::endl;
    
      return 0;
    }
    
    template <typename NumberType, int bitCount,
              std::enable_if_t<!doBitCountsMatch<NumberType>(bitCount), int> = 0>
    auto test() -> NumberType
    {
      std::cout << "Bit counts don't match." << std::endl;
    
      return 0;
    }
    

    Demo