Consider the following code example
#include <iostream>
#include <experimental/optional>
std::experimental::optional<int> dflt(42);
template<const std::experimental::optional<int>& Dflt>
void foo() {
if (Dflt) {
std::cout << "default is set" << std::endl;
} else {
std::cout << "default is not set" << std::endl;
}
}
int main() {
foo<dflt>(); // <-- OK
foo<std::experimental::nullopt>(); // <-- NOT OK
}
What I am trying to achieve is to pass nullopt
as a non-type function template parameter but it doesn't compile. It works with a global variable dflt
with static storage though.
The compiler error message looks like this:
foo.cc: In function ‘int main()’:
foo.cc:13:34: error: no matching function for call to ‘foo()’
foo<std::experimental::nullopt>();
^
foo.cc:7:6: note: candidate: template<const std::experimental::fundamentals_v1::optional<int>& Dflt> void foo()
void foo() {
^
foo.cc:7:6: note: template argument deduction/substitution failed:
foo.cc:13:34: error: could not convert template argument ‘std::experimental::fundamentals_v1::nullopt’ to ‘const std::experimental::fundamentals_v1::optional<int>&’
foo<std::experimental::nullopt>();
I know the example is silly, but my main question is, can nullopt
be passed as non-type template parameter at all?
A template non-type parameter is a template parameter where the type of the parameter is predefined and is substituted for a constexpr value passed in as an argument. A non-type parameter can be any of the following types: An integral type. An enumeration type. A pointer or reference to a class object.
A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.
NoneType is the type for the None object, which is an object that indicates no value. None is the return value of functions that "don't return anything".
In UML models, template parameters are formal parameters that once bound to actual values, called template arguments, make templates usable model elements. You can use template parameters to create general definitions of particular types of template.
The longer answer has to do with the constraints placed on template arguments. Your template parameter is of a reference type. The corresponding argument for it must fulfill the requirements in [temp.arg.nontype]/2 (emphasis mine):
A template-argument for a non-type template-parameter shall be a converted constant expression of the type of the template-parameter. For a non-type template-parameter of reference or pointer type, the value of the constant expression shall not refer to (or for a pointer type, shall not be the address of):
- a subobject,
- a temporary object,
- a string literal,
- the result of a typeid expression, or
- a predefined func__ variable.
nullopt
is a constant of the type nullopt_t
. Which is quite plainly not an optional<int>
. As such, to bind that const reference we will need to materialize a temporary. But that explicitly makes the program ill-formed, as the text in bold indicates.
Mind you however, that you can have the parameter be a reference to a nullopt_t
. Then you can pass nullopt
for the argument. Though the utility of such a template is limited, I'd say.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With