简体   繁体   中英

Choose template function based on existence of member

Let's say you have these two classes:

class A
{
 public:
     int a;
     int b;
}

class B
{
 public:
     int a;
     int b;
}

class C
{
 public:
     float a1;
     float b1;
}

enum class Side { A, B };

I want a template function which takes a side and a T , and depending on the T , returns a reference to " Ta " or " Tb " if the class has a member T::a , or a reference to " T.a1 " or " T.b1 " if the class has a member T::a1 .

My starting point is:

template<typename T>
auto &GetBySide(const Side &side, const T &twoSided) 
{ 
  return side == Side::A?twoSided.a:twoSided.b; 
}

template<typename T>
auto &GetBySide(const Side &side, const T &twoSided) 
{ 
  return side == Side::A?twoSided.a1:twoSided.b1; 
}

The question is how to get the compiler to skip the first template if the member a does not exist.

So I implemented the solution given by @Jarod42 below, but it gave errors in VS 2015 because of a bug in VS ability to differentiate between templates. Here is a work around:

template<typename T>
auto GetBySide(const Side &side, const T& twoSided) 
-> decltype((twoSided.a))
{ 
  return side == Side::A ? twoSided.a : twoSided.b; 
}

// Using comma operator to trick compiler so it doesn't think that this is the same as above
template<typename T>
auto GetBySide(const Side &side, const T &twoSided) 
-> decltype((0, twoSided.a1))
{ 
  return side == Side::A ? twoSided.a1 : twoSided.b1; 
}

// See comment above
template<typename T>
auto GetBySide(const Side &side, const T &twoSided) 
-> decltype((0, 0, twoSided.a2))
{ 
  return side == Side::A ? twoSided.a2 : twoSided.b2; 
}

Another way would be to use the comma operator and a special struct which represented each "concept"

With SFINAE.

template<typename T>
auto GetBySide(const Side &side, const T& twoSided) 
-> decltype((twoSided.a))
{ 
  return side == Side::A ? twoSided.a : twoSided.b; 
}

template<typename T>
auto GetBySide(const Side &side, const T &twoSided) 
-> decltype((twoSided.a1))
{ 
  return side == Side::A ? twoSided.a1 : twoSided.b1; 
}

Demo

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