Checking if a variant type can hold a type T

86 views
Skip to first unread message

Christopher Di Bella

unread,
May 10, 2017, 6:45:32 AM5/10/17
to ISO C++ Standard - Future Proposals
Hi everyone,

I'd like to get a feel for whether or not a type_trait would be welcome for checking if a variant type can hold a type T.

Currently, we have `holds_alternative`, which requires an object, and can't be evaluated at compile-time for all expressions.
We also have `variant_alternative_t`, but this requires indexing, and leaves implementing a check to the programmer(s) that need it.

This would be really handy for constraining classes to only accept types their variants actually take.

```
using Example = std::variant<int, double, std::vector<int>>;

template <typename T> // or enable_if, if you don't have concepts available
requires
   can_hold_v<Example, T>
class Foo {
public:
   const T& example() const noexcept
   {
      return std::get<T>(example_);
   }
private:
   Example example_;
};
```

I asked about this on the Cpplang Slack channel, and Jason Turner helped me with an implementation at https://godbolt.org/g/p6WUa4.

Please let me know your thoughts.

Cheers,

Chris

Matt Calabrese

unread,
May 10, 2017, 10:20:45 AM5/10/17
to ISO C++ Standard - Future Proposals
On Wed, May 10, 2017 at 6:45 AM, Christopher Di Bella <cjd...@gmail.com> wrote:
Hi everyone,

I'd like to get a feel for whether or not a type_trait would be welcome for checking if a variant type can hold a type T.

Currently, we have `holds_alternative`, which requires an object, and can't be evaluated at compile-time for all expressions.
We also have `variant_alternative_t`, but this requires indexing, and leaves implementing a check to the programmer(s) that need it.

This would be really handy for constraining classes to only accept types their variants actually take.

Based on your desired usage, you want something slightly different from what you've requested and different from the implementation you've linked. You actually want to determine if there is *exactly one* match (as opposed to 0 or multiple).

Christopher Di Bella

unread,
May 10, 2017, 7:10:55 PM5/10/17
to ISO C++ Standard - Future Proposals
I don't have any use cases for zero or multiple matches, but only checking for exactly one match seems like an unnecessary constraint overall.

Would it be a good idea to think of some good cases for zero and multiple matches, and then come back?

Cheers, 

Chris


--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CANh8DEnmoKd6v4E2M17M-c7SdkUtbwfGy6v_bK4kuhC5%3DwC0SA%40mail.gmail.com.

Arthur O'Dwyer

unread,
May 10, 2017, 8:36:43 PM5/10/17
to ISO C++ Standard - Future Proposals
As Matt Calabrese said in this thread: it seems like there are a whole lot of possible semantics here, and you've picked at least two of them.
- "Example matches std::variant<Ts...> where at least one of the Ts is T"
- "Example matches std::variant<Ts...> where exactly one of the Ts is T"
- "Example matches std::variant<Ts...> where exactly one of the Ts is implicitly convertible from T"
- "Example is implicitly convertible from T"
- "std::get<T>(std::declval<Example>()) is well-formed"
etc. etc.

If you really wanted to write your Foo class template today in C++17, I'd argue for writing it like this:

template <typename T, typename Enabled = decltype(std::get<T>(std::declval<Example>()))>
class Foo {

I think there's a market for metaprogramming utilities in the standard library that would let us write Jason's example as simply std::meta::contains<std::meta::as_typelist<Example>, T>; but I don't think that really solves your question because your question is ill-defined.

HTH,
Arthur

T. C.

unread,
May 11, 2017, 2:15:34 AM5/11/17
to ISO C++ Standard - Future Proposals


On Wednesday, May 10, 2017 at 8:36:43 PM UTC-4, Arthur O'Dwyer wrote:

If you really wanted to write your Foo class template today in C++17, I'd argue for writing it like this:

template <typename T, typename Enabled = decltype(std::get<T>(std::declval<Example>()))>
class Foo {

 
Last time I checked, std::get isn't required to be SFINAE-friendly. 
Reply all
Reply to author
Forward
0 new messages