2

Is there a way to switch member variable initalization based on a template parameter?

Some enable_if trick or something similar?

I could do something like this with a lambda call

template<bool A>
struct Test{

  static constexpr int a = [](){
    if constexpr(A) return 1; else return 2;}();

};

but this fails for my actual use case with a look up array (also tried with std:array)

template<bool A>
struct Test{
  // A==true variant
  static constexpr std::int8_t table[4] {1,2,3,4};
  // A==false variant
  //static constexpr std::int8_t table[4] {4,6,7,3};
3
  • 2
    It would have been more fruitful to show the code that produces an error, rather than code that works and code with comments that allude to not working. There are no guarantees we "reconstruct" your attempt and see the error. Commented Jun 4 at 21:42
  • the actual question seems to be "how to conditionally initialize an array?" For the accepted answer it doesnt even matter that its inside a template. Commented Jun 5 at 6:41
  • C-array doesn't have copy constructor, so you cannot do it that way for C-array, but it should work for std::array. Commented Jun 5 at 7:18

2 Answers 2

6

You can indeed use a lambda that will return a std::array according to the value of A

#include <array>
#include <cstdint>

template<bool A>
struct Test {
  static constexpr auto table = [] {
      if (A)  { return std::array<std::int8_t,4> {1,2,3,4}; }
      else    { return std::array<std::int8_t,4> {4,6,7,3}; }
  }();
};

static_assert (Test<true> ::table == std::array<std::int8_t,4> {1,2,3,4});
static_assert (Test<false>::table == std::array<std::int8_t,4> {4,6,7,3});

int main() {}

Demo

Sign up to request clarification or add additional context in comments.

3 Comments

Note your static_assert's won't compile prior to C++20. In any case, the lambda can be simplified by using an explicit return type rather than auto: []() -> std::array<std::int8_t,4> { if (A) { return {1,2,3,4}; } else { return {4,6,7,3}; } } and you might consider using if constexpr rather than a normal if
@RemyLebeau, good point. For c++20, I was a little bit lazy on that one since it's more convenient to write static_assert that checks array content ;)
As you don't use if constexpr, ternary operator might even be used instead of IIFE: return A ? std::array<std::int8_t,4> {1,2,3,4} : std::array<std::int8_t,4> {4,6,7,3};
5

Here's an old-school way of doing it which uses a class template with a specialization. I'm using plain C arrays here, not because it's preferable, but to show that it's possible.

This works from C++11 and up:

#include <cstdint>

template <bool>
struct Test {
    static constexpr std::int8_t table[4]{1, 2, 3, 4};
};

template <>
struct Test<false> {
    static constexpr std::int8_t table[4]{4, 6, 7, 3};
};

static_assert(Test<true>::table[0] == 1 && Test<true>::table[1] == 2 &&
              Test<true>::table[2] == 3 && Test<true>::table[3] == 4, "");
static_assert(Test<false>::table[0] == 4 && Test<false>::table[1] == 6 &&
              Test<false>::table[2] == 7 && Test<false>::table[3] == 3, "");

If you want table as a member of a class with other members, you can use inheritance:

template <bool>
struct table_def {
    static constexpr std::int8_t table[4]{1, 2, 3, 4};
};

template <>
struct table_def<false> {
    static constexpr std::int8_t table[4]{4, 6, 7, 3};
};

template<bool A>
struct Test : table_def<A> {
    // other members...
};

Comments

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.