6

I need to check if the nth element of a tuple is an optional of some type. It has to be an std::optional and not a std::variant (which could have made the code simpler).

My first instinct is the following. But this throws a compiler error.

template<int N, typename TupleToCheck>
void StaticCheck() {
    using NthType = typename tuple_element<N, TupleToCheck>::type;
    static_assert(std::is_same<NthType, std::optional<NthType::value_type>>);
}

I suspect that this is because the compiler does not know if NthType could have a type value_type defined within it. Is there a way to achieve this?

Sway
  • 317
  • 1
  • 7
  • 1
    Be aware of [Rice's theorem](https://en.wikipedia.org/wiki/Rice%27s_theorem). Perhaps C++ is not the best language for coding that. Did you consider using [Agda](https://en.wikipedia.org/wiki/Agda_(programming_language)) instead of C++ ? Look also into [Frama-C](http://frama-c.com/), or use some meta-programming approach: generate some of your C++ code (like we try to do in [RefPerSys](http://refpersys.org/)...) – Basile Starynkevitch Sep 23 '20 at 20:19
  • What error does this produce? – 0x5453 Sep 23 '20 at 20:22
  • 1
    It works for me (no compilation errors) if I correct syntax errors: https://godbolt.org/z/dxndEx. Added `std::`, `typename `, and `::value`. – Daniel Langr Sep 23 '20 at 20:30
  • @DanielLangr yep that fixed it. so I guess compiler assumes any unknown variable is a value, but the keyword typename convinces it otherwise? – Sway Sep 23 '20 at 20:35
  • @Sway It is called a dependent name and yes, the compiler cannot distinguish whether it is a type or a value on its own, [see](https://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-the-template-and-typename-keywords). – Quimby Sep 23 '20 at 20:36

2 Answers2

1

You did not post the error, but this scheme should work for all templates regardless whether ::value_type exists:

#include <tuple>
#include <optional>


template<typename T>
struct is_optional{
    constexpr static bool value = false;
};

template<typename T>
struct is_optional<std::optional<T>>{
    constexpr static bool value = true;
};

template<typename T>
constexpr bool is_optional_v = is_optional<T>::value;

template<int N, typename TupleToCheck>
void StaticCheck() {
    static_assert(is_optional_v<std::tuple_element_t<N,TupleToCheck>>);
}


int main(){

    using t1 = std::tuple<int,std::optional<double>,double>;

    StaticCheck<1,t1>();
}
Quimby
  • 17,735
  • 4
  • 35
  • 55
  • Thanks @Quimby, this should work, but I believe the code with the fix by DanielLangr is simpler and more concise. – Sway Sep 23 '20 at 20:39
  • 1
    @Sway Definitely agree. He should make it an answer, even if it was basically just a typo. – Quimby Sep 23 '20 at 20:39
0

Answering my own question for the sake of closure.

The issue with my code was syntax, as @DanielLangr pointed out in the comments.

It works for me (no compilation errors) if I correct syntax errors: godbolt.org/z/dxndEx. Added std::, typename , and ::value.

The fixed code is as below

template<int N, typename TupleToCheck>
void StaticCheck() {
    using NthType = typename std::tuple_element<N, TupleToCheck>::type;
    static_assert(std::is_same<NthType, std::optional<typename NthType::value_type>>::value);
}
Sway
  • 317
  • 1
  • 7