8

Given next working solution:

template<typename T, typename = void>
struct has_value_t : std::false_type { };

template<typename T>
struct has_value_t<T, decltype(T::value, void())> : std::true_type { };

template<typename T>
constexpr bool has_value = has_value_t<T>::value;

Idea was taken from https://stackoverflow.com/a/14523787/3743145

I wonder if there a C++17/20 more laconic way to achieve same effect. Like

template<typename T>
constexpr bool has_value = .....;

Usage:

template<typename T>
enable_if_t<has_value<T>,
std::ostream&> operator<<(std::ostream& os, T const& arg)
{
    return os << arg.value;
}
kyb
  • 7,233
  • 5
  • 52
  • 105
  • 1
    There is potentially [std::experimental::is_detected](https://en.cppreference.com/w/cpp/experimental/is_detected). – Jarod42 Mar 12 '20 at 09:19

2 Answers2

7

If C++20 is on the table, you can do that with a concept that checks a simple requirement

template <typename T>
concept has_value = requires(T) {
    T::value;
};

template<typename T> requires has_value<T>
std::ostream& operator<<(std::ostream& os, T const& arg)
{
    return os << arg.value;
}

T::value being a well formed expression is being checked in the requires expression. Pretty straight forward to write, and to use as a constraint on a template.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
3

In

template<typename,typename=void> constexpr bool has_value = false;
template<typename T>             constexpr bool has_value<T,decltype(T::value,void())> = true;

Test

struct V { int value; };
struct W { int walue; };

static_assert(has_value<V>);
static_assert(not has_value<W>);

Thanks to https://stackoverflow.com/a/52291518/3743145

kyb
  • 7,233
  • 5
  • 52
  • 105