c++metaprogramming

Getting object member at compile time


I'd like to make a compile-time map in which I'll connect a number to a member of a class. Then return member of a class from a function at compile-time.

This is the current code

class MyClass
{
public:
    float MemberA;
    std::uint32_t MemberB;
};

int ProcessMember(int iMemberID, MyClass* pClass)
{
    if (iMemberID == 1){
        ProcessMember(pClass->MemberA);
    }
    else if (iMemberID == 2){
        ProcessMember(pClass->MemberB);
    }
    endif
}

This is what I'd like to do:

template <class T>     
void Multiply(T& CurrentValue)     
{
    CurrentValue = CurrentValue * 2;
}

int ProcessMember(int iMemberID, MyClass* pClass)
{
   if (iMemberID == 1){
      Multiply(func(1));
    }
   else if (iMemberID == 2){
      Multiply(func(2));
    }
   endif
}

So the function will take a compile-time argument and will point to the member of MyClass that I want it to.

Is this possible?

I tried this:

template <typename T>         
T& GetValueFromValueName(int MemberID, MyClass* pClass)         
{            
    switch (MemberID) 
    {             
        case 1:                 
            return pClass>MemberA;             
        case 2:                 
            return pClass->MemberB;         
    }
}

But this only compiles if I specify T in advance before calling the function.


Solution

  • The return type of a function cannot be determined at runtime but it must be known at compile time.

    You can make memberID a template argument, then either use specializations:

    template <int memberID>
    auto& GetValueFromValueName(MyClass* pClass);
    
    template <>
    auto& GetValueFromValueName<1>(MyClass* pClass) { return pClass->MemberA; }
    template <>
    auto& GetValueFromValueName<2>(MyClass* pClass) { return pClass->MemberB; }
    

    Or constexpr if:

    template <int memberID>
    auto& GetValueFromValueName(MyClass* pClass) { 
        if constexpr (memberID == 1) return pClass->MemberA;
        else return pClass->MemberB;
    }
    

    This is what I'd like to do: [...]

    I suppose what you actually want is to not spell out each case individually, because if you do that there is no benefit of writing test(1) instead of pClass->MemberA. With the above you can write:

    template <int memberID>
    auto ProcessMember(MyClass* pClass)
    {
        return Multiply(GetValueFromValueName<memberID>(pClass));
    }