suannai
suannai

Reputation: 13

variadic class constructor with a templated class as argument

I seem to have a hard time describing my problem, so I was unsuccessful searching for previous answers.

I have the next code written in c++17 - It has Data class which can hold a templated argument (and size_t as id). Next I have a DataBase class that holds a tuple of Data instances. Than in main, I have an example for a DataBase instance with different Data types, but the user maliciously inserted into the database a non-Data class variable. I need to prevent it.

// a data to be in the database
template <size_t ID, class T>
class Data
{
   public:
    Data(T var) : m_var(var) {}

    size_t id = ID;
    T m_var;
};

//Here is the database. How should I only accept Data class with different template type... 
template <class... DATA_TYPES>
class DataBase
{
  public:
    DataBase(DATA_TYPES... args) : m_data(args...) {}
    std::tuple<DATA_TYPES...> m_data;
};



int main() {
 
    DataBase d(Data<0, int>(10),
               Data<1, char>(40),
                "an invalid member"); //<------- should not be able to compile  
}

The code attempts to make my question clear. I want to make class database accept Data instances with different template arguments (as seen in main func), but not accept any other type of data.

If I am generalizing my template line as <class... DATA_TYPES>, maybe I can use some static assert or "constexpr if" in the ctor, but there should be a way to change the template line to accept only Data class type with variadic different types (and size_t as ID) template..

Help will be appreciated!

Upvotes: 1

Views: 38

Answers (1)

super
super

Reputation: 12928

You need a way to determine if a type is an instatiation of Data. One way is to use partial template specialization on a template variable.

Once we have that we throw in a static_assert in Database.

#include <tuple>

// a data to be in the database
template <std::size_t ID, class T>
class Data
{
   public:
    Data(T var) : m_var(var) {}

    std::size_t id = ID;
    T m_var;
};

template <typename T>
constexpr bool isData = false;

template <std::size_t ID, typename T>
constexpr bool isData<Data<ID, T>> = true;

//Here is the database. How should I only accept Data class with different template type... 
template <class... DATA_TYPES>
class DataBase
{
    static_assert((isData<DATA_TYPES> && ...));
  public:
    DataBase(DATA_TYPES... args) : m_data(args...) {}
    std::tuple<DATA_TYPES...> m_data;
};



int main() {
    DataBase d(Data<0, int>(10),
               Data<1, char>(40),
                "an invalid member"); //<------- should not be able to compile  
}

Upvotes: 1

Related Questions