Reputation: 62797
I'd like to implement this functionality with C++ templates as nicely as possible.
struct Foo {
int x = 0;
int y = 0;
};
struct Bar {
int x = 1;
};
// I want to call this function for both Foo and Bar instances
template <typename T>
int helperFunc(const T &item) {
// many lines of code I don't want to repeat
int result = item.x;
result += item.x;
result *= item.x;
// only do code below if item has y
result += item.y;
return result;
}
Constraints: I can not alter Foo
or Bar
, so I can't for example add abstract interface superclass for Foo
. I don't want to specialize the function specifically for any named class either, and I don't want to repeat any logic code.
My current, rather dumb solution is to have template <typename T> int helperFunc(const T &item, int y = 0) {...};
, and then for a Foo
call it like helperFunct(aFoo, aFoo.y)
, which works for my use case, but is not very nice. I'd like to put the decision to use y
inside the template. I tried to find something applicable from here, but couldn't really come up with a way to use any of that to achieve the above.
Upvotes: 1
Views: 240
Reputation: 172924
You can make type trait to check whether the type has the member y
or not.
template <typename T, typename = void>
struct has_y : std::false_type {};
template <typename T>
struct has_y<T, std::void_t<decltype(std::declval<T>().y)>>
: std::true_type {};
then you can apply constexpr if (since C++17).
if constexpr (has_y<T>::value) // only do code below if item has y
result += item.y;
Upvotes: 2
Reputation: 2754
You can use SFINAE on function overloads to check for the existence of y
, then use if-constexpr
:
template <typename T>
std::true_type hasY_ (decltype(std::declval<T> ().y)*);
template <typename T>
std::false_type hasY_ (...);
template <typename T>
static constexpr bool hasY = decltype(hasY_<T>(0))::value;
// I want to call this function for both Foo and Bar instances
template <typename T>
int helperFunc(const T &item) {
// many lines of code I don't want to repeat
int result = item.x;
result += item.x;
result *= item.x;
// only do code below if item has y
if constexpr (hasY<T>)
result += item.y;
return result;
}
Upvotes: 4