C++ - Defining 2 template parameters but calling with only 1 - c++

While working on a project I came upon this code, which I'm trying to figure out:
enum Attributes { ACTIVE, COMPLETE, POSITION }
template<Attributes NN,typename TT>
TT& Set(TT&& t)
{
return typeList.get<NN>()=t; //typeList is a boost tuple
}
This is called later on with
object.Set<ACTIVE>(true);
There's only one template parameter in there!
How is possible to specify a template with two parameters, and then call it with only one? I would think the Set method supposed to take 2 template parameters (Attributes and typename), like an std::map.

The second one is deduced fom the type of argument passed to a function, in this case bool.

When calling a function template template parameters, which are the type of the function arguments can be automatically deduced from the type of the arguments, the function is called with:
object.Set<ACTIVE>(true); //same as object.Set<Active,bool>(true);
object.Set<ACTIVE>(5); //same as object.Set<Active,int>(5);
This is the reason one can use template functions from the standardlibrary, like std::max or std::copy without explicitely mentioning the types of the arguments.

Read this.
When a function template specialization is referenced, all of the
template arguments shall have values. The values can be explicitly
specified or, in some cases, be deduced from the use or obtained from
default template-arguments.
[ Example:
void f(Array<dcomplex>& cv, Array<int>& ci) {
sort(cv); // calls sort(Array<dcomplex>&)
sort(ci); // calls sort(Array<int>&)
}
and
void g(double d) {
int i = convert<int>(d); // calls convert<int,double>(double)
int c = convert<char>(d); // calls convert<char,double>(double)
}
—end example ]
and 14.8.2 par of this doc. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf

Related

Why does std::apply fail with function template, but not with a lambda expression with explicit template parameter list?

In looking at std::apply references from cpprefrence we can see that function templates cannot be passed as callable object of std::apply. Let's consider the following function template:
template<typename T>
T add_generic(T first, T second) { return first + second; }
So as the function template can't be deduced in std::apply call, we can't use the follwing code:
std::apply(add_generic, std::make_pair(2.0f, 3.0f)); // Error: can't deduce the function type
Please note that this is not the same question as this question. In that answer, the author writes a lambda expression without explicit template parameters.
std::cout << std::apply(
[](auto first, auto second) { return add_generic(first, second); },
std::make_tuple(2.0f,3.0f)) << '\n';
but as you know in c++20 you can have lambda expressions with explicit template parameter list. So I tried this feature to the case and surprisingly the compiler did not raise any errors.
std::apply([]<typename T>(T first,T second){
return first+second;
},std::make_pair(2.0,3.0));
Why will the compiler be able to deduce type in the last case? Is there any difference between the two?
A function template is not a function, just like a cookie cutter is not a cookie. C++ templates create new functions for every set of template arguments. And this is precisely why add_generic is not a viable argument. It's not a function, it cannot be passed around as a value. To obtain the function, the compiler needs to deduce the template arguments. But it can only do that inside apply after the callable has been passed. Chicken and egg right there.
Why does a lambda work? Because it's not a plain function either. It produces a hidden object type
struct __lambda_at_line_N {
template<typename T>
auto operator()(T first, T second) { /* ... */ }
};
And passes that
std::apply(__lambda_at_line_N{},std::make_pair(2.0,3.0));
This is an actual object, a value. Its type does not depend on the template argument deduction that needs to happen inside std::apply to call operator(). That's why it works.

No clue... Is the specialised default argument confused the template type deduction? [duplicate]

I was surprised the following code resulted in a could not deduce template argument for T error:
struct foo
{
template <typename T>
void bar(int a, T b = 0.0f)
{
}
};
int main()
{
foo a;
a.bar(5);
return 0;
}
Calling a.bar<float>(5) fixes the issue. Why can't the compiler deduce the type from the default argument?
In C++03, the specification explicitly prohibits the default argument from being used to deduce a template argument (C++03 §14.8.2/17):
A template type-parameter cannot be deduced from the type of a function default argument.
In C++11, you can provide a default template argument for the function template:
template <typename T = float>
void bar(int a, T b = 0.0f) { }
The default template argument is required, though. If the default template argument is not provided, the default function argument is still not usable for template argument deduction. Specifically, the following applies (C++11 14.8.2.5/5):
The non-deduced contexts are:
...
A template parameter used in the parameter type of a function parameter that has a default argument that is being used in the call for which argument deduction is being done.
There would be some technical difficulties in achieving that in general. Remember that default arguments in templates are not instantiated until they are needed. Consider then:
template<typename T, typename U> void f(U p = T::g()); // (A)
template<typename T> T f(long, int = T()); // (B)
int r = f<int>(1);
This is resolved today by performing (among other things) the following steps:
attempt to deduce template parameters for candidates (A) and (B);
this fails for (A), which is therefore eliminated.
perform overload resolution; (B) is selected
form the call, instantiating the default argument
In order to deduce from a default argument, that default argument would have to be itself instantiated before completing the deduction process. That could fail, leading to errors outside the SFINAE context. I.e., a candidate that may be entirely inappropriate for a call could trigger an error.
A good reason might be that
void foo(bar, xyzzy = 0);
is similar to a pair of overloads.
void foo(bar b) { foo(b, 0); }
foo(bar, xyzzy);
Moreover, sometimes it is advantageous to refactor it into such:
void foo(bar b) { /* something other than foo(b, 0); */ }
foo(bar, xyzzy);
Even when written as one, it's still like two functions in one, neither of which is "preferred" in any sense. You're calling the one-argument function; the two-argument one is effectively a different function. The default argument notation just merges them into one.
If overloading were to have the behavior that you are asking for, then for consistency it would have to work in the case when the template is split up into two definitions. That wouldn't make sense because then the deduction would be pulling types from an unrelated function that is not being called! And if it was not implemented, it would mean that overloading different parameter list lengths becomes a "second class citizen" compared to "default-argumenting".
It is good if the difference between overloads and defaulting is completely hidden to the client.

Template deduction from default argument [duplicate]

I was surprised the following code resulted in a could not deduce template argument for T error:
struct foo
{
template <typename T>
void bar(int a, T b = 0.0f)
{
}
};
int main()
{
foo a;
a.bar(5);
return 0;
}
Calling a.bar<float>(5) fixes the issue. Why can't the compiler deduce the type from the default argument?
In C++03, the specification explicitly prohibits the default argument from being used to deduce a template argument (C++03 §14.8.2/17):
A template type-parameter cannot be deduced from the type of a function default argument.
In C++11, you can provide a default template argument for the function template:
template <typename T = float>
void bar(int a, T b = 0.0f) { }
The default template argument is required, though. If the default template argument is not provided, the default function argument is still not usable for template argument deduction. Specifically, the following applies (C++11 14.8.2.5/5):
The non-deduced contexts are:
...
A template parameter used in the parameter type of a function parameter that has a default argument that is being used in the call for which argument deduction is being done.
There would be some technical difficulties in achieving that in general. Remember that default arguments in templates are not instantiated until they are needed. Consider then:
template<typename T, typename U> void f(U p = T::g()); // (A)
template<typename T> T f(long, int = T()); // (B)
int r = f<int>(1);
This is resolved today by performing (among other things) the following steps:
attempt to deduce template parameters for candidates (A) and (B);
this fails for (A), which is therefore eliminated.
perform overload resolution; (B) is selected
form the call, instantiating the default argument
In order to deduce from a default argument, that default argument would have to be itself instantiated before completing the deduction process. That could fail, leading to errors outside the SFINAE context. I.e., a candidate that may be entirely inappropriate for a call could trigger an error.
A good reason might be that
void foo(bar, xyzzy = 0);
is similar to a pair of overloads.
void foo(bar b) { foo(b, 0); }
foo(bar, xyzzy);
Moreover, sometimes it is advantageous to refactor it into such:
void foo(bar b) { /* something other than foo(b, 0); */ }
foo(bar, xyzzy);
Even when written as one, it's still like two functions in one, neither of which is "preferred" in any sense. You're calling the one-argument function; the two-argument one is effectively a different function. The default argument notation just merges them into one.
If overloading were to have the behavior that you are asking for, then for consistency it would have to work in the case when the template is split up into two definitions. That wouldn't make sense because then the deduction would be pulling types from an unrelated function that is not being called! And if it was not implemented, it would mean that overloading different parameter list lengths becomes a "second class citizen" compared to "default-argumenting".
It is good if the difference between overloads and defaulting is completely hidden to the client.

Why do we have to specify <> for a template class with default parameters?

I find something annoying in C++ and I don't know if there is a trick to avoid this with no overhead. The problem is the following :
For a template function, we can have :
// Function declaration/definition
template<bool Option = false> void myFunction()
{
std::cout<<"Option = "<<Option<<std::endl;
}
// Then I can use :
myFunction<false>();
myFunction<true>();
myFunction(); // <- NO PROBLEM HERE
Now for a template class :
// Class definition/declaration
template<bool Option = false> class MyClass
{
};
// Then I can use :
myClass<false> x;
myClass<true> y;
myClass z; // <- PROBLEM HERE : only "MyClass<> z;" will compile !
Why is the reason of this behaviour ?
Is there any trick to avoid that ?
For a class with optionnal parameters passed as template, I find this not convenient for the end user : he should be able to use the default implementation as a no-templated class...
Why is the reason of this behaviour ?
It's because functions can be overloaded, and types can't.
When you write a function call, the compiler populates an overload set of all the functions it can find with that name, and then figures out which ones match the argument(s) passed. Now, for this to work cleanly with function templates, it allows the template argument types to be deduced from the parameters. Because type parameter inference is allowed in general, it works for your case even when the parameter is defaulted instead.
Types, however, aren't overloaded. While myFunction<true>() and myFunction<false>() are both related to the extent they'll participate in the same overload set, myClass<true> and myClass<false> are separate and unrelated types. With no equivalent of overloading on type names, there's no motivation to add a special case for implicitly naming a fully-specialized template class. The parameters can never be inferred, so it would amount to special syntax only for the case where they're all defaulted.
Is there any trick to avoid that ?
In general, if you want to get template argument deduction for template classes, you can provide a template function wrapper (this works best with C++11 auto)
template <bool Option=false> class MyClass {};
template <bool Option=false> MyClass<Option> make_my_class() {
return MyClass<Option>();
}
// ...
auto z = make_my_class();
Otherwise, I think using typedef (as per Remy's comment) is the best option.
myClass is a class template, not a class. Only myClass<true>, or myClass<>, is a class.
Similarly, myFunction is a function template, not a function. However, when you're invoking a temp­la­ted function, the template arguments may be deduced for you, and you don't need to specify template arguments explicitly if they can be deduced. Thus the function call expression myFunction(); is valid, and the first argument is deduced as false. It's just that the deduction happens thanks to the default argument rather than matching against function arguments.

Why can't the compiler deduce the template type from default arguments?

I was surprised the following code resulted in a could not deduce template argument for T error:
struct foo
{
template <typename T>
void bar(int a, T b = 0.0f)
{
}
};
int main()
{
foo a;
a.bar(5);
return 0;
}
Calling a.bar<float>(5) fixes the issue. Why can't the compiler deduce the type from the default argument?
In C++03, the specification explicitly prohibits the default argument from being used to deduce a template argument (C++03 §14.8.2/17):
A template type-parameter cannot be deduced from the type of a function default argument.
In C++11, you can provide a default template argument for the function template:
template <typename T = float>
void bar(int a, T b = 0.0f) { }
The default template argument is required, though. If the default template argument is not provided, the default function argument is still not usable for template argument deduction. Specifically, the following applies (C++11 14.8.2.5/5):
The non-deduced contexts are:
...
A template parameter used in the parameter type of a function parameter that has a default argument that is being used in the call for which argument deduction is being done.
There would be some technical difficulties in achieving that in general. Remember that default arguments in templates are not instantiated until they are needed. Consider then:
template<typename T, typename U> void f(U p = T::g()); // (A)
template<typename T> T f(long, int = T()); // (B)
int r = f<int>(1);
This is resolved today by performing (among other things) the following steps:
attempt to deduce template parameters for candidates (A) and (B);
this fails for (A), which is therefore eliminated.
perform overload resolution; (B) is selected
form the call, instantiating the default argument
In order to deduce from a default argument, that default argument would have to be itself instantiated before completing the deduction process. That could fail, leading to errors outside the SFINAE context. I.e., a candidate that may be entirely inappropriate for a call could trigger an error.
A good reason might be that
void foo(bar, xyzzy = 0);
is similar to a pair of overloads.
void foo(bar b) { foo(b, 0); }
foo(bar, xyzzy);
Moreover, sometimes it is advantageous to refactor it into such:
void foo(bar b) { /* something other than foo(b, 0); */ }
foo(bar, xyzzy);
Even when written as one, it's still like two functions in one, neither of which is "preferred" in any sense. You're calling the one-argument function; the two-argument one is effectively a different function. The default argument notation just merges them into one.
If overloading were to have the behavior that you are asking for, then for consistency it would have to work in the case when the template is split up into two definitions. That wouldn't make sense because then the deduction would be pulling types from an unrelated function that is not being called! And if it was not implemented, it would mean that overloading different parameter list lengths becomes a "second class citizen" compared to "default-argumenting".
It is good if the difference between overloads and defaulting is completely hidden to the client.