Asymmetric custom template template

I am trying to define a template class that has a template parameter of a non-user-defined type. Unfortunately, we haven't succeeded yet. The actual code is too long, but a simplified example looks like this:

#include <iostream>

template <class T>
class Maybe {
    bool is_ = false;
    T value_;

  public:
    constexpr Maybe() = default;
    constexpr Maybe(T value) : is_(true), value_(value) {}

    constexpr bool is() const { return is_; }
};

template <Maybe<int> parm>
struct Test {
    void say() const {
        std::cout << "parm is " << (parm.is() ? "set" : "not set") << ".\n";
    }
};

int main() {
    Test<Maybe<int>{}> not_set;
    Test<Maybe<int>(2)> is_set;

    not_set.say();
    is_set.say();
}

      

When I try to compile this code (with Clang 3.4) I get the following error message:

test.cc:15:22: error: a non-type template parameter cannot have type
      'Maybe<int>'
template <Maybe<int> parm>
                     ^
test.cc:23:10: error: value of type 'Maybe<int>' is not implicitly
      convertible to 'int'
    Test<Maybe<int>{}> not_set;
         ^~~~~~~~~~~~
test.cc:24:10: error: value of type 'Maybe<int>' is not implicitly
      convertible to 'int'
    Test<Maybe<int>(2)> is_set;
         ^~~~~~~~~~~~~
3 errors generated.

      

Now I know that a non-python type template parameter must fulfill some conditions . However, I thought that being constexpr would be enough. Or could it be just one of the built-in integral types?

Is there a way to pass non-python template parameters to my own custom type?

+3


source to share


3 answers


this whole problem is the very reason why rational numbers are implemented as a template class with the actual numbers in the template parameters. to get a template parameter storing more than just int, you must create a similar class as std::ratio

, which is also only evaluated at compile time.

as for your actual example, consider writing something similar to:

template<class T, T ... Params>
class Maybe {

      

and then



Test<Maybe<int,5> > is_set;

      

or

Test<Maybe<int> > not_set;

      

+2


source


No, you cannot.

n3376 14.1 / 7

A non-type template parameter must not be declared as a floating point, class, or void.

template<double d> class X; // error
template<double* pd> class Y; // OK
template<double& rd> class Z; // OK

      



so you can pass a pointer or reference, but not a class object.

live example

+6


source


I know this question is old, but I would like to point out the template metaprogram approach.

In C ++, you can pass any type to a template like this, so why not just make it a type?

To do this, you will want to create a wrapper class for the Maybe class:

template <typename T>
struct maybe_wrap 
{
    Maybe<T> value{};
}

template<typename T, T value>
struct maybe_wrap
{
    Maybe<T> value{value};
}

      

Then just pass the maybe_wrap parameter as filename and just access maybe_wrap<int, 3>().value

it when you need it!

The only limitation of this is that T cannot be one of the non-type values ​​(int, bool, etc.).

In this case, use the above logic again!

+1


source







All Articles