1

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

8
  • The values of args are not compile-time constants. So when the function is compiled, there is no way for the compiler to check the static assertion. You could be calling the function with any arguments. If you need this, make the function parameters template parameters instead. Commented Jun 2, 2022 at 8:37
  • @user17732522 Yes, this was already explained here. This is a follow up question by OP. Commented Jun 2, 2022 at 8:38
  • @SupAl If you add static_assert(arr.back() == 4); inside the CreateArrConst then it won't work either. Demo. The reason is the same as explained in here and also by user17732522. I think you should phrase this follow up question a little differently so that it won't be the same as the original here. Commented Jun 2, 2022 at 8:40
  • @AnoopRana, Hey again! That's exactly the issue with the first variant - that I cannot do the static_assert, so that's why I tried to make the array constexpr, but to no avail. What I do not understand is the following: 1) In the first case, at compile time it can create a constexpr array that can be returned and checked in the main function. 2) If I try to do the constexpr before returning it, it's not possible. So how can it instantiate the constexpr in the first place if the arguments are not constexpr? Commented Jun 2, 2022 at 8:43
  • 1
    @SupAl I have modified your question to make it more clear, can you see and confirm if it matches your intention. Commented Jun 2, 2022 at 8:51

1 Answer 1

1

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;
}
Sign up to request clarification or add additional context in comments.

4 Comments

Since C++17 auto as type will work with deduction.
Is auto... the same as T...? Meaning all the same type? Although I guess it will just fail to create the array if the types don't match.
No, it doesn't enforce equal types, but neither does OP's function template. However, the CTAD for std::array will fail if the types are not all equal in either case.
This works great. An even more clean solution (requiring C++17) is to do as suggested by @user17732522 and just write template<auto... args>. In that case the parameters can be auto deduced.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.