2

I'm trying to solve type deduction issue.

Here's the demo code, that uses function overloading to define, whether the passed variable is int or double


std::string tcast( const double &x){ return "Floating Point";};
std::string tcast( const int    &x){ return "Integer";};

int main(){
    double dA;
    int    iB;
    std::cout << "Access to variable type \n";
    std::cout << "dA : "<< tcast( dA )<< std::endl;
    std::cout << "iB : "<< tcast( iB )<< std::endl;
}
Access to variable type 
dA : Floating Point
iB : Integer

But this function doesn't work for non-static class members:

struct Foo{
    double dA;
    int    iB;
};

int main(){

    std::cout << "Member dA : "<< tprint( &Foo::dA )<< std::endl;
    std::cout << "Member iB : "<< tprint( &Foo::iB )<< std::endl;

}

GCC compilation error:

main.cpp: In function ‘int main(int, char**)’:
main.cpp:111:44: error: no matching function for call to ‘tcast(double Foo::*)’
  111 |     std::cout << "dA : "<< tcast( &Foo::dA )<< std::endl;
      |                                            ^
main.cpp:96:13: note: candidate: ‘std::string tcast(const double&)’
   96 | std::string tcast( const double &x){ return "Floating Point";};
      |             ^~~~~
main.cpp:96:34: note:   no known conversion for argument 1 from ‘double Foo::*’ to ‘const double&’
   96 | std::string tcast( const double &x){ return "Floating Point";};
      |                    ~~~~~~~~~~~~~~^
main.cpp:97:13: note: candidate: ‘std::string tcast(const int&)’
   97 | std::string tcast( const int    &x){ return "Integer";};
      |             ^~~~~
main.cpp:97:34: note:   no known conversion for argument 1 from ‘double Foo::*’ to ‘const int&’
   97 | std::string tcast( const int    &x){ return "Integer";};
      |                    ~~~~~~~~~~~~~~^

But the following code compiles :

template <typename T>
std::string tprint( const T    &x){ return typeid(x).name();};
...
std::cout << "dA : "<< tprint( dA )<< std::endl;
std::cout << "iB : "<< tprint( iB )<< std::endl;
std::cout << "Member dA : "<< tprint( &Foo::dA )<< std::endl;
std::cout << "Member iB : "<< tprint( &Foo::iB )<< std::endl;

And so it's visible for compiler that dA has type double and iB int

dA : d
iB : i
Member dA : M3Food  // ends in d
Member iB : M3Fooi  // ends in i

So what should be the right way to deduct the type of the non-static data member?

2 Answers2

4

We can use template argument deduction to our advantage here. Pointer to member data's syntax is

DataType Class::*Pointer

After deducing the member type we can call the required overload.

template<typename Class, typename MemType>
std::string tcast(MemType Class::*mData){
    return tcast(MemType{});
}

Link to the code in godbolt

Ch3steR
  • 20,090
  • 4
  • 28
  • 58
2

You might add extra overload:

template <typename C>
std::string tprint(double C::*){ return "member Floating Point";};

template <typename C>
std::string tprint(int C::*){ return "member Integer";};

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302