Having this template:
template <bool X>
struct Foo {
Foo(int v) : v(v) {}
int v;
};
I can say that by default Foo
should be of False
with deduction guide:
Foo(int)->Foo<false>;
Thank's to which this code works:
Foo a = 5;
My problem is, how can i make this work when Foo
is used as function argument:
template <bool X>
void f(Foo<X> foo) {
cout << "Foo<" << X << ">(" << foo.v << ")" << endl;
}
f(5); // error: no matching function for call to 'f'
// candidate template ignored: could not match 'Foo<X>' against 'int'
I tried saying somehow f
that X
is by default false
but f
(I mean compiler) is not listening to me:
template <bool X = false> // = false changes nothing, same error
void f(Foo<X> foo) {
cout << "Foo<" << X << ">(" << foo.v << ")" << endl;
}
template <bool X>
struct get_bool { // to force looking at f::X
static constexpr bool value = X;
};
template <bool X = false>
void f(Foo<get_bool<X>::value> foo) {
cout << "Foo<" << X << ">(" << foo.v << ")" << endl;
/* this is not working because
* get_bool evaulates before
* args matching and in the end,
* this function could be defined
* as: void f(Foo<false>)
*/
}
I don't mind introducing some additional helper classes etc.
I was hoping that maybe some decltype
, auto
, some_trait<>
or additional helper class (/es) magic could help here to solve this problem which I think I could also sum up as:
How to define a deduction guide for function?
The problem with template <bool X = false> void f(Foo<X> foo)
is that implicit conversions are not allowed when passing arguments to parameters that are used in template parameter deduction.
You can either add an extra overload of f
accepting an int
, or not make f
a template at all:
struct Bar
{
bool x = false;
int v = 0;
template <bool X>
Bar(Foo<X> foo) : x(X), v(foo) {}
Bar(int v) : v(v) {}
};
void f(Bar bar) {...}
It means the boolean is no longer constexpr
inside of f
. If you want it to be constexpr
, there's a trick you can use:
void f(Bar bar)
{
auto lambda = [&](auto x_value)
{
constexpr bool x = x_value;
// Here `x` is `constexpr`.
};
if (bar.x)
lambda(std::true_type{});
else
lambda(std::false_type{});
}