Search code examples
c++templatesvariadic-templates

Creating a constexpr array from non-constexpr argument


I learnt from here that args is not a constant expression. Now my question is: What should I modify in the given program so that I will be able to have an static_assert in the first variant without getting a compile time error.

In the following code:

#include <array>

template<typename... Args>
auto constexpr CreateArrConst(Args&&... args)
{
  std::array arr
  {
      args...
  };
  //i want to have an static_assert here without error
  return arr;
}

template<typename... Args>
auto constexpr CreateArrConst_NotWorking(Args&&... args)
{
  constexpr std::array arr
  {
      args...
  };
  static_assert(arr.back() == 4);
  return arr;
}

int main() 
{
  static_assert(CreateArrConst(4).back() == 4);
  // uncomment this to reproduce compile error
  // static_assert(CreateArrConst_NotWorking(4).back() == 4);

  return 0;
}

Here's a link to reproduce: https://godbolt.org/z/zjrP1Kvn7


Solution

  • You have to put the arguments into template parameters. Unfortunately it then can't deduce the type of the arguments anymore:

    #include <array>
    
    template<typename T, T... args>
    auto constexpr CreateArrConst()
    {
      constexpr std::array arr
      {
          args...
      };
      static_assert(arr.back() == 4);
      return arr;
    }
    
    // cleaner solution requiring C++17
    template<auto... args>
    auto constexpr CreateArrConstCpp17()
    {
      constexpr std::array arr
      {
          args...
      };
      static_assert(arr.back() == 4);
      return arr;
    }
    
    int main() 
    {
      static_assert(CreateArrConst<int, 4>().back() == 4);            // <-- Works!
    
      static_assert(CreateArrConstCpp17<1, 2, 3, 4>().back() == 4);
      return 0;
    }