简体   繁体   中英

Function specialization to access struct members with getter using enum

I have an enum and a struct

enum STORE_ENUM { A_DATA, B_DATA, C_DATA, D_DATA };
struct Store {
   int a;
   char b;
   long c;
   bool d;

}

and I want to access its members with a specialized get function that basically looks like this

T get(STORE_ENUM,store s);

and it returns the appropriate type and hopefully statically type checks. is this possible in C++?

Yes it's possible. The boost PFR library allows something very similar to how you've envisaged it, eg:

auto& x = boost::pfr::get<B_DATA>(s);

See the tutorial here .

With C++17, you can do the following

#include <iostream>

enum struct STORE_ENUM { A_DATA, B_DATA, C_DATA, D_DATA };
struct Store {
   int a;
   char b;
   long c;
   bool d;

};

template<STORE_ENUM storeEnum>
auto get(Store const & s){
    if constexpr (storeEnum == STORE_ENUM::A_DATA) return s.a;
    if constexpr (storeEnum == STORE_ENUM::B_DATA) return s.b;
    if constexpr (storeEnum == STORE_ENUM::C_DATA) return s.c;
    if constexpr (storeEnum == STORE_ENUM::D_DATA) return s.d;
}
int main(){
    auto store = Store{ 0, 'a', 4l, true};
    std::cout << get<STORE_ENUM::A_DATA>( store) << "\n";
    std::cout << get<STORE_ENUM::B_DATA>( store) << "\n";
    std::cout << get<STORE_ENUM::C_DATA>( store) << "\n";
    std::cout << get<STORE_ENUM::D_DATA>( store) << "\n";
}

See https://godbolt.org/z/1vffh3

In my solution, we don't need enums. It uses templates.

#include <iostream>
#include <type_traits>

struct Store
{
    int a;
    char b;
    long c;
    bool d;

    Store() //Default constructor
    {
        a = 0;
        b = 0;
        c = 0;
        d = false;
    }

    Store(int a, char b, long c, bool d) //Constructor. Custom values.
    {
        this->a = a;
        this->b = b;
        this->c = c;
        this->d = d;
    }

    template <typename T = int,
              typename = typename std::enable_if<std::is_same<T, int>::value ||
                                                     std::is_same<T, char>::value ||
                                                     std::is_same<T, long>::value ||
                                                     std::is_same<T, bool>::value,
                                                 void>::type>
    T GetData()
    {
        if (std::is_same<T, char>::value)
        {
            return b;
        }
        if (std::is_same<T, long>::value)
        {
            return c;
        }
        if (std::is_same<T, bool>::value)
        {
            return d;
        }
        return a;
    }
};

int main()
{
    Store store { 63, '@', 65, true };
    std::cout << store.GetData() << std::endl;
    std::cout << store.GetData<>() << std::endl;
    std::cout << store.GetData<int>() << std::endl;
    std::cout << store.GetData<char>() << std::endl;
    std::cout << store.GetData<long>() << std::endl;
    std::cout << std::boolalpha << store.GetData<bool>() << std::endl;
}

Output

63
63
63
@
65
true

Compile clang++./main.cpp -std=c++11 or g++./main.cpp -std=c++11

Check/run this code in https://repl.it/@JomaCorpFX/FunctionSpecialization#main.cpp

std::tuple basically does this, and your type is basically a tuple. So the easy and fast way is to just reuse std::tuple 's machinery.

In it might look like this:

template<STORE_ENUM e>
auto get( Store s ){
  return std::get<(unsigned)e>(std::make_tuple(s.a,s.b,s.c,s.d));
}
template<STORE_ENUM e, class T>
void set( Store& s, T t ){
  std::get<(unsigned)e>(std::tie(s.a,s.b,s.c,s.d))=t;
}

This is , but the missing bit for is easy:

template<STORE_ENUM e>
using store_type = typename std::tuple_element<(unsigned)e, std::tuple<int,char,long,bool>>::type;

template<STORE_ENUM e>
store_type<e> get( Store s ) {
  return std::get<(unsigned)e>(std::make_tuple(s.a,s.b,s.c,s.d));
}

template<STORE_ENUM e>
void set( Store& s, store_type<e> v ){
  std::get<(unsigned)e>(std::tie(s.a,s.b,s.c,s.d))=v;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM