I can infer template parameters with function parameters
template <typename T>
void f(T a)
{ /* */ }
f(4); // T inferred to be `int`
However I can't use function parameters to infer template parameters, which aren't types:
template <int I>
void g(int I) // error: declaration of 'I' shadows template parameter
{ /* */ }
Let's say I want to write a function divive_dy_2(int number) and I want to make sure number is not zero.
I've seen a very simple way to do this, which would require me to pass the argument to a template parameter, which then would use SFINAE to disable it, if it was 0.
But it feels counter-intuitive to expose something like this in an API. Is there some workaround?
(And yes, I could use exceptions and what not, what would probably even be a better idea, but I'm learning SFINAE at the moment and want to know where it's limits are)
If your argument is known at compile time, you do not even need sfinae for your check - a simple assert will provide much better diagnostics.
However, if the argument is not known (which is more likely scenario) than you can not make it template argument, and you have to use exceptions or return error code to indicate that provided argument is outside of supported domain.
Think of template as smth the same as #define
If you want to use 4 as template argument, it's roughly
template <int I>
void g()
{ ... here use I as _value_, not type}
You can quickly look in Alexandrescu's C++ book for a longer discussion, how to use values in template arguments.
Related
Lets assume I have a template function
template <typename T>
void do_sth(T const&);
For some types ("small" and copyable) it would be better to pass an argument by value instead of reference.
So my question is: What is the simplest way to overload a function depending on the underlying type?
Remark:
Best what I came to is using enable_if with some conditions of "simple" type. And I believe there's no such a type trait as "simple type" in the standard library. Correct me if I'm wrong. Moreover: Using enable_if gets complicated as a function takes more template arguments (edited) because template <typename T, typename U> void do_sth(T, U) would need 4 overloads: (value, value), (value, ref), (ref, value) and (ref, ref).
Don't do this. Template functions are inlined at the drop of a hat, and a reference to an x is an alias with no identity once the function is inlined.
Encourage the function to be inlined instead of doing a mess of SFINAE, unless and until you have proven this to be an important bottleneck.
After discovering this function is taking up more time than anything else you can optimize, test its improvement by manualy writing the by value version in a couple of key cases to ensure you actually get a benefit (I doubt you will).
boost has call_traits:
template <typename T>
void do_sth(typename boost::call_traits<T>::param_type)
But one big issue is that T is no longer deducible
(and so you have to call it do_sth<int>(42) or do_sth<MyBigObj>(myBigObj)).
So might be used for non template methods in template class:
template <typename T>
struct S
{
void do_sth(typename boost::call_traits<T>::param_type);
};
But anyway, chances are that compiler actually inlines code, resulting in same generated code.
I wonder why template specializations make sense?
Aren't the following things equivalent?
Template specialization:
template <typename T>
void f(T t) {
something(t);
}
template <>
void f<int>(int t) {
somethingelse(t);
}
Non-template function instead of specialization:
void f(int t) {
somethingelse(t);
}
I believe these are the same because the non-template function will always be preferred.
This is the answer I came up with:
It's different if the template parameter is not a parameter of the function being defined:
template <typename T>
void f() {
T t;
something(t);
}
template <>
void f<int>() {
int t;
somethingelse(t);
}
In this case defining:
void f() {
int t;
somethingelse(t);
}
would make all the template versions unuseable.
Maybe somebody else has better ideas. :)
The question boils down to determining when the specialization will be used that the overload cannot. There are different situations where this is the case although they are uncommon enough, and it is simple enough to make mistakes that the general recommendation is to prefer overloads to specializations.
When the caller explicitly requests the use of a template. In the code example you provide if the call is f<int>(42) or even f<42>(), then the overload will not be used.
When you cannot provide the required overloads, or the overload cannot be resolved at the place of call. For example if the type is not one of the function arguments (it is either not present in the signature at all or only in the return type:
template
T f();
In this case, you cannot provide overloads int f(); and double f(); but you can provide as many template specializations as you need, and it will be up to the user to force the selection of one or the other. Note that this could be considered a subcase of the previous case: because the template arguments take no part in the function arguments, the user needs to provide the template arguments, so the call is explicitly to a template.
When you want to place special constraints on the combination of arguments and inhibit implicit conversions:
template
void f( T, T ); // Both argument must be the same type
Because template argument deduction only perform perfect matches, this template can only be used when both arguments are of the exact same type, if you add an overload void f(int,int) that overload can be used with any combination of types that are implicitly convertible to int, like f( 5, 3.0 ), but the specialization won't.
In general, for most cases, none of the cases above really apply, so an overload should be preferred.
There might be more, but those are the ones I can recall off the top of my head
The way you declare the function does matter if you insist on calling it like f<int>(42). This will find the specialization, but not the overload.
If the call always looks like f(42), either alternative will work.
Function template specialization is deprecated in favor of function overloads with one exception: you are allowed to add a function template specialization to the std namespace, you aren't allowed to add a new function. So, if you need to supply a specific version for something in the std namespace, you have to use template specialization. For instance, to support creating an unordered_map with a user-defined class as the key you have to specialize std::hash for your class.
struct A
{
template <class U>
void f(U)
{
}
};
template <class T>
void f(T t)
{
A a;
a.template f<int>(t);
a.template f<>(t);
a.f<int>(t);
a.f<>(t);
a.f(t);
}
At least under MSVC2010 the above code compile fine.
Among all the manners to call A.f is there any preferentials way to do this?
Is there any differences ?
Well, a has type A, which is not a dependent type in this context. So the template keyword is not needed and only serves to obfuscate the code -- don't use it.
The version that invokes a template without supplying any arguments, again does nothing to change behavior and only makes the code less readable -- don't use it either.
Between the two remaining candidates, a.f(t) and a.f<int>(t), use the first in most cases, and the second if the compiler fails to deduce the type.
The last one seems easiest to write.
Otherwise there are no differences, unless you have to disambiguate between several f's.
No differences at all. If you don't have any reason to provide type information to the function, the last one is the best. But you may want your function to process arguments as if they are of the specified type, only then, should you need <>. For example
T Divide(T a, T b)
{
return a/b;
}
If you call Divide(5,2), you get 2. Only cases like this, should you specify type:
Divide<float>(5,2);
It returns 2.5.
In C++ you can create templates using a non-type template parameter like this:
template< int I >
void add( int& value )
{
value += I;
}
int main( int argc, char** argv )
{
int i = 10;
add< 5 >( i );
std::cout << i << std::endl;
}
Which prints "15" to cout. What is the use for this? Is there any reason for using a non-type template parameter instead of something more conventional like:
void add( int& value, int amount )
{
value += amount;
}
Sorry if this has already been asked (I looked but couldn't find anything).
There are many applications for non-type template arguments; here are a few:
You can use non-type arguments to implement generic types representing fixed-sized arrays or matrices. For example, you might parameterize a Matrix type over its dimensions, so you could make a Matrix<4, 3> or a Matrix<2, 2>. If you then define overloaded operators for these types correctly, you can prevent accidental errors from adding or multiplying matrices of incorrect dimensions, and can make functions that explicitly communicate the expected dimensions of the matrices they accept. This prevents a huge class of runtime errors from occur by detecting the violations at compile-time.
You can use non-type arguments to implement compile-time function evaluation through template metaprogramming. For example, here's a simple template that computes factorial at compile-time:
template <unsigned n> struct Factorial {
enum {
result = n * Factorial<n - 1>::result
};
};
template <> struct Factorial<0> {
enum {
result = 1
};
};
This allows you to write code like Factorial<10>::result to obtain, at compile-time, the value of 10!. This can prevent extra code execution at runtime.
Additionally, you can use non-type arguments to implement compile-time dimensional analysis, which allows you to define types for kilograms, meters, seconds, etc. such that the compiler can ensure that you don't accidentally use kilograms where you meant meters, etc.
Hope this helps!
You're probably right in this case, but there are cases where you need to know this information at compile time:
But how about this?
template <std::size_t N>
std::array<int, N> get_array() { ... }
std::array needs to know its size at compile time (as it is allocated on the stack).
You can't do something like this:
std::array<int>(5);
Well, this the typical choice between compile-time polymorphism and run-time polymorphism.
From the wording of your question in appears that you see nothing unusual in "ordinary" template parameters, while perceiving non-type parameters as something strange and/or redundant. In reality the same issue can be applied to template type parameters (what you called "ordinary" parameters) as well. Identical functionality can often be implemented either through polymorphic classes with virtual functions (run-time polymorphism) or through template type parameters (compile-time polymorphism). One can also ask why we need template type parameters, since virtually everything can be implemented using polymorphic classes.
In case of non-type parameters, you might want to have something like this one day
template <int N> void foo(char (&array)[N]) {
...
}
which cannot be implemented with a run-time value.
In that particular instance, there's not really any advantage. But using template parameters like that, you can do a lot of things you couldn't do otherwise, like effectively bind variables to functions (like boost::bind), specify the size of a compile-time array in a function or class (std::array being a ready example of that), etc.
For instance, with that function, you write a function like
template<typename T>
void apply(T f) {
f(somenum);
}
Then you can pass apply a function:
apply(&add<23>);
That's an extremely simple example, but it demonstrates the principle. More advanced applications include applying functions to every value in a collection, calculating things like the factorial of a function at compile time, and more.
You couldn't do any of that any other way.
There are lots of reasons, like doing template metaprogramming (check Boost.MPL). But there is no need to go that far, C++11's std::tuple has an accessor std::get<i> that needs to be indexed at compile time, since the result is dependent on the index.
The most frequent use for a value parameter that I can think of is std::get<N>, which retrieves the Nth element of a std::tuple<Args...>. The second-most frequent use would be std::integral_constant and its main derivatives std::true_type and std::false_type, which are ubiquitous in any sort of trait classes. In fact, type traits are absolutely replete with value template parameters. In particular, there are SFINAE techniques which leverage a template of signature <typename T, T> to check for the existence of a class member.
If we've this function template,
template<typename T>
void f(T param) {}
Then we can call it in the following ways,
int i=0;
f<int>(i);//T=int : no need to deduce T
f(i); //T=int : deduced T from the function argument!
//likewise
sample s;
f(s); //T=sample : deduced T from the function argument!
Now consider this variant of the above function template,
template<typename TArg, typename TBody>
void g(TArg param)
{
TBody v=param.member;
}
Now, can the compiler deduce the template arguments if we write,
sample s;
g(s); //TArg=sample, TBody=int??
Suppose sample is defined as,
struct sample
{
int member;
};
There are basically two questions:
Can the compiler deduce the template arguments in the second example?
If no, then why? Is there any difficulty? If the Standard doesn't say anything about "template argument deduction from function body", then is it because the argument(s) cannot be deduced? Or it didn't consider such deduction so as to avoid adding more complexity to the language? Or what?
I would like know your views on such deduction.
EDIT:
By the way, the GCC is able to deduce function arguments if we write this code:
template<typename T>
void h(T p)
{
cout << "g() " << p << endl;
return;
}
template<typename T>
void g(T p)
{
h(p.member); //if here GCC can deduce T for h(), then why not TBody in the previous example?
return;
}
Working demonstration for this example : http://www.ideone.com/cvXEA
Not working demonstration for the previous example: http://www.ideone.com/UX038
You probably already concluded that the compiler won't deduce TBody by examining the type of sample.member. This would add yet another level of complexity to the template deduction algorithm.
The template matching algorithm only considers function signatures, not their bodies. While not used too often, it's perfectly legal to simply declare a templated function without providing the body:
template <typename T> void f(T param);
This satisfies the compiler. In order to satisfy the linker, you must of course also define the function body somewhere, and ensure that all required instantiations have been provided. But the function body does not necessarily have to be visible to client code of the template function, as long as the required instantiations are available at link time. The body would have to explicitly instantiate the function, eg:
template <> void f(int param);
But this only partially applies to your questions, because you could imagine a scenario like the following, where a 2nd parameter could be deduced from the a provided default parameter, and which won't compile:
template<typename TArg, typename TBody>
void g(TArg param, TBody body = param.member); // won't deduce TBody from TArg
The template matching algorithm considers only the actual type, not any potential nested member types in case of classes or structs. This would have added another level of complexity which apparently was judged to be too complex. Where should the algorithm stop? Are members of members, and so forth, also to be considered?
Also, it's not required because there are other means of achieving the same intention, as shown in the example below.
Nothing prevents you from writing:
struct sample
{
typedef int MemberType;
MemberType member;
};
template<typename TArg>
void g(TArg param)
{
typename TArg::MemberType v = param.member;
}
sample s = { 0 };
g(s);
in order to obtain the same effect.
Regarding your sample you added after editing: whereas it seems that h(p.member) does depend on the member of the struct, and hence the template matching algorithm should fail, it doesn't because you made it a two-step process:
Upon seeing g(s);, the compiler looks for any function taking an argument of type sample (templated or not!). In your case, the best match is void g(T p). At this point, the compiler has not even looked at the body of g(T p) yet!.
Now, the compiler creates a instance of g(T p), specialized for T: sample. So when it sees h(p.member) it knows that p.member is of type int, and will try locate a function h() taking an argument of type int. Your template function h(T p) turns out to be the best match.
Note that if you had written (note the NOT_A_member):
template<typename T>
void g(T p)
{
h(p.NOT_A_member);
return;
}
then the compiler would still consider g() a valid match at stage 1. You then get an error when it turns out that sample does not have a member called NOT_A_member.
There are a couple of things that the compiler cannot possibly do with the code that you provide, the first of which is deduce the second template argument TBody. First, type deduction is only applied to the arguments of the function when the compiler is trying to match the call. At that point the definition of the templated function is not even looked at.
For extra credits, even if the compiler were to look the function definition, the code TBody v = parameter.member is non-deducible in itself, as there are potentially infinite data types that can accept a parameter.member in the constructor.
Now, on the second block of code. To understand it the whole process of template compilation starts when the compiler sees the function call g(x) at that point of call. The compiler sees that the best candidate is the template function template <typename T> void g( T ) and determines what the type T is as part of the overload resolution. Once the compiler determines that it is a call to the template, it performs the first pass of compilation on that function.
During the first pass, syntactic checks are perform without an actual substitution of the type, so the template argument T is still any-type and the argument p is of a yet-unknown type. During the first pass, the code is verified, but dependent names are skipped and their meaning is just assumed. When the compiler sees p.member, and p is of type T that is a template argument it assumes that it will be a member of the yet unknown type (this is the reason why if it is a type you would have to qualify it here with typename). The call h(p.member); is also dependent on the type argument T and is left as it is, assuming that once the type substitution takes place everything will make sense.
Then the compiler does actually substitute the type. At this step T is no longer a generic type, but it represents the concrete type sample. Now the compiler during the second pass tries to fill in the gaps that were left during the first pass. When it sees p.member it looks member inside the type and determines that it is an int and tries to resolve the call h( p.member ); with that knowledge. Because the type T has been resolved before this second stage, this is equivalent to the outside call g(x): all types are known and the compiler only needs to resolve what is the best overload for a function call h that takes an argument of type int&, and the whole process starts again, the template h is found as the best candidate, and ...
It is really important for metaprogramming to understand that type deduction is performed only on the actual signature of the function and not the body, and that is what makes it non-trivial for beginners. Using enable_if (from boost or elsewhere) in the function signature as argument or return type is not a coincidence, but the only way of having the compiler fail to substitute the type before the template is selected as best candidate and the substitution failure is turned into an actual error (and not SFINAE)
No compiler could possibly implement this functionality in a consistent manner. You are simply asking too much.
TBody might be ambiguous, because sample might not be the only type that has a member member. Furthermore, if g calls other template functions, the compiler has no way of knowing what other restrictions might be imposed on TBody.
So in some edge cases, it is theoretically possible to deduce the proper type for TBody, generally it is not.