Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can the class member can be changed depending on the template args in c++

Tags:

c++

c++98

I want the class member can be changed depending on the template args. I want something like follow

template<int value>
class MyClass
{
public:
   void print()
   {
      // using the member
      std::cout << sizeData() << std::endl;
      for (int i=0;i<sizeData();i++)
      {
         std:cout << data[i] << std::endl;
      }
   }
   static int sizeData()
   {
     #if value == 1
        return 3;
     #endif
     #if value == 2
        return 6;
     #endif
   }
   static int sizeArray()
   {
     #if value == 1
        return 40;
     #endif
     #if value == 2
        return 200;
     #endif
   }
private:
   #if value == 1
      int data[3];
      const static int array[40];
   #endif
   #if value == 2
      int data[6];
      const static int array[200];
   #endif
}

I do not know can it be implemented in c++.

Thanks for your time.

add

Many sir already give the answer in C++11 and C++17. Thanks all your's advises.

If the code can be settled in C++98, it will be perfect. Because my code should run on a platform which only support C++98.

like image 436
Xu Hui Avatar asked Jan 24 '23 16:01

Xu Hui


2 Answers

You can use std::conditional to pick which member you would like to have like

template<int value>
class MyClass
{
public:
   static int sizeData()
   {
       return (value == 1) ? 3 : 6; // needs to be improved
   }
   static int sizeArray()
   {
       return sizeof(array) / sizeof(array[0]);  // size of array divided by size of element is then number of elements in the array
   }
private:

   std::conditional_t<value == 1, int[3], int[6]> data;
   const static std::conditional_t<value == 1, int[40], int[200]> array;

};

While std::conditional is not a part of C++98, it's implemented only using C++98 C++, so you can make you own using the possible implementation from the reference site link. You can see that working with

#include <iostream>

template<bool B, class T, class F>
struct conditional { typedef T type; };
 
template<class T, class F>
struct conditional<false, T, F> { typedef F type; };

template<int value>
class MyClass
{
public:
    static int sizeData()
    {
       return (value == 1) ? 3 : 6; // needs to be improved
    }
    static int sizeArray()
    {
       return sizeof(array) / sizeof(array[0]);
    }
private:

    typename conditional<value == 1, int[3], int[6]>::type data;
    const static typename conditional<value == 1, int[40], int[200]>::type array;

};

int main()
{
    MyClass<1> m;
    std::cout << m.sizeData();
}

in this live example.


This kind of falls apart for sizeData since data is not static but the function is. To avoid code duplication, instead of using std::conditional, we can use the enum trick to get compile time constants for the sizes of the array and use that like

#include <iostream>

template<int value>
class MyClass
{
public:
    static int sizeData()
    {
       return data_size; // now improved
    }
    static int sizeArray()
    {
       return array_size;
    }
private:
    enum { data_size = (value == 1) ? 3 : 6 }; // this is required to be a compile time constant
    enum { array_size = (value == 1) ? 40 : 200 }; // these need to become before the array members
    int data[data_size]; // less verbose
    const static int array[array_size];
};

int main()
{
    MyClass<1> m;
    std::cout << m.sizeData();
}
    
    
like image 57
NathanOliver Avatar answered Jan 27 '23 07:01

NathanOliver


You can use if constexpr and immediately evaluated constexpr lambdas.

Disclaimer: it is C++ 17 only, need extra brackets that enclose the lambda in order to compile, and I really wouldn't recommend to use this code as it is. It's purpose is demonstration only!

template<int value>
class MyClass
{
public:
   static int sizeData()
   {
     if constexpr(value == 1)
        return 3;
     
     if constexpr (value == 2)
        return 6;     
   }
   static int sizeArray()
   {
     if constexpr (value == 1)
        return 40;
     
     if constexpr (value == 2)
        return 200;
   }
private:
    int data[([](int v) constexpr { if (v == 1) return 3; if (v==2) return 6; }(value))];
    const static int array[([](int v) constexpr { if (v == 1) return 40; if (v==2) return 200; }(value))]; 
};

int main()
{
   MyClass<1> m1;
   MyClass<2> m2;
}
like image 40
Vasilij Avatar answered Jan 27 '23 06:01

Vasilij