Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
124 views
in Technique[技术] by (71.8m points)

std::optional as template non-type parameter in C++?

I want to have non-type optional template parameters in my class/struct.

Of cause I can do:

template <bool has_arg0, int arg0>
struct S {};

and use S<true, 123> if there is value for arg0 and S<false, 0> if there is no value.

But would be nice to have just one template parameter instead of two.

For that first I tried to use std::optional:

Try it online!

#include <optional>

template <std::optional<size_t> X>
struct S {};

int main() {}

but above code doesn't compile with error error: 'std::optional<long unsigned int>' is not a valid type for a template non-type parameter because it is not structural. Looks like std::optional is not suitable for template non-type parameters.

Then I tried to implement my own solution:

Try it online!

#include <iostream>
#include <optional>

template <typename T>
struct Optional {
    constexpr Optional() = delete;
    constexpr Optional(nullptr_t) {}
    template <typename OT>
    constexpr Optional(OT const & val)
        : has_value(true), value(val) {}
    bool const has_value = false;
    T const value = T();
};

template <Optional<size_t> X = nullptr>
struct S {
    static constexpr auto x = X;
};

int main() {
    {
        S<123> s;
        std::cout << std::boolalpha << s.x.has_value << " " << s.x.value << std::endl;
    }
    {
        S<nullptr> s;
        std::cout << std::boolalpha << s.x.has_value << " " << s.x.value << std::endl;
    }
    {
        S s;
        std::cout << std::boolalpha << s.x.has_value << " " << s.x.value << std::endl;
    }
}

which compiles and works on recent compilers.

My question is whether there is some standard-library solution for this? Maybe there exists some std::optional-like class in standard library but suitable for template params, basically which does similar stuff as my Optional class in code above?

Also small accompanying question is what else besides nullptr I can use to initialize optional without value? Maybe there is some standard-library definition like struct null_type_t {}; which can be used everywhere to pass null-value?

question from:https://stackoverflow.com/questions/65542144/stdoptional-as-template-non-type-parameter-in-c

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

What about using variadic templates ?

#include <type_traits>
#include <iostream>

template <typename T, T...>
struct O;

template <typename T, T val>
struct O<T, val>
 {
   static constexpr bool has_value { true };

   using type = T;

   T value { val };
 };

template <typename T>
struct O<T>
 {
   static constexpr bool has_value { false };

   using type = T;
 };

template <typename...>
struct S;

template <char ... Cs, int ... Is, long ... Ls, long long ... Lls,
          bool ... Bs>
struct S<O<char, Cs...>, O<int, Is...>, O<long, Ls...>,
         O<long long, Lls...>, O<bool, Bs...>>
 {
   O<char,      Cs...>   v1;
   O<int,       Is...>   v2;
   O<long,      Ls...>   v3;
   O<long long, Lls...>  v4;
   O<bool,      Bs...>   v5;

 };

int main ()
 {
   S<O<char>, O<int, 123>, O<long>, O<long long>, O<bool, true>>  s;

   std::cout << s.v1.has_value << std::endl;
   std::cout << s.v2.has_value << ", " << s.v2.value << std::endl;
   std::cout << s.v3.has_value << std::endl;
   std::cout << s.v4.has_value << std::endl;
   std::cout << s.v5.has_value << ", " << s.v5.value << std::endl;
 }

If you can use C++17, you can simplify a little, using auto for the type of the value but maintaining the requirements abut the type of the optional for S (an optional char, an optional int, an optional long, an optional long long and an optional bool).

#include <iostream>

template <auto ...>
struct O;

template <auto val>
struct O<val>
 {
   static constexpr bool has_value { true };

   using type = decltype(val);

   type value { val };
 };

template <>
struct O<>
 { static constexpr bool has_value { false }; };

template <typename...>
struct S;

template <char ... Cs, int ... Is, long ... Ls, long long ... Lls,
          bool ... Bs>
struct S<O<Cs...>, O<Is...>, O<Ls...>, O<Lls...>, O<Bs...>>
 {
   O<Cs...>   v1;
   O<Is...>   v2;
   O<Ls...>   v3;
   O<Lls...>  v4;
   O<Bs...>   v5;
 };

int main ()
 {
   S<O<>, O<123>, O<>, O<>, O<true>>  s;

   std::cout << s.v1.has_value << std::endl;
   std::cout << s.v2.has_value << ", " << s.v2.value << std::endl;
   std::cout << s.v3.has_value << std::endl;
   std::cout << s.v4.has_value << std::endl;
   std::cout << s.v5.has_value << ", " << s.v5.value << std::endl;
 }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...