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?
source to share
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;
source to share
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.
source to share
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!
source to share