Suppose I have a function template where the type parameter is used as a return type only:
template <typename T>
T foo()
{
return whatever;
}
Then what is the correct syntax to specialize that function template? Both of the following seem to work:
template <>
std::string foo()
{
return whatever;
}
template <>
std::string foo<std::string>()
{
return whatever;
}
Is there any difference between the two? If not, what is the idiomatic way?
The compiler will deduce the correct template specialization based on informations provided (here, the function return type).
So these syntaxes have exactly the same behaviour, one being more explicit than the other.
In most case, there is no difference between the two.
If you overload several template functions, the second form may be needed to remove an ambiguity about which overload you mean to specialize (you probably have other problems if you are in this situation, for instance you'll also need to be explicit at call places).
Related
I've got the following code:
template <bool condition>
struct enable_if { };
template <>
struct enable_if<true> { using type = bool; };
template <typename T>
class is_callable {
using Yes = char[1];
using No = char[2];
template <typename U> static Yes& filter(decltype(&U::operator()));
template <typename U> static No& filter(...);
public:
constexpr operator bool() { return sizeof(filter<T>(nullptr)) == sizeof(Yes); }
};
template <typename Lambda, typename enable_if<is_callable<Lambda>{}>::type = true>
void doSomethingWithLambda(Lambda func) {
func();
}
int main() {
doSomethingWithLambda([]() { });
}
The important part is the enable_if<is_callable<Lambda>{}>::type part.
One is forced to instantiate is_callable<Lambda> with {} because if one were to use (), C++ would mistake it for a function call.
Feel free to correct me if I'm wrong, but as far as I know, C++ assumes it is a function in the () case so that the type of expression isn't determined after the time of writing, saving everyone a headache. What I mean by that is, assuming you had a function version and a class version of is_callable (separated by SFINAE using enable_if or something along those lines), the type Lambda could determine the true meaning of (), either a function call or an instantiation. Like I said, as far as I know, C++ wants to avoid this confusion, so it assumes function call and fails if such a function does not exist.
Based on the assumptions above, the following shouldn't work:
enable_if<(bool)is_callable<Lambda>()>::type
What does it matter if I cast the result of the function call (never mind that functions couldn't even be evaluated in this context)? Why is this suddenly treated as an instantiation instead of a function call?
No, your understanding is not correct.
Firstly, a name can't refer to both a class template and a function template. If that happens the program is ill-formed. (And defining both in the same scope is not allowed to begin with.)
Secondly, is_callable<Lambda>() as template argument is not a function call to begin with. It is a function type. It is the type of a function which has no parameters and returns a is_callable<Lambda>.
When the compiler parses a template argument, it can interpret it in two ways: Either as a type or as an expression (or as a braced-init-list), because template parameters can be type parameters or non-type parameters.
When the compiler reads is_callable<Lambda>() it notices that is_callable is a class template and then realizes that is_callable<Lambda> is therefore a type. If you have a type, let's shorten it to T, then T() can either be syntax representing the type of a function returning T and taking no arguments, or it can be an expression formed from one single functional notation explicit cast (which you imprecisely call "instantiation").
There is no way to differentiate these two cases in the context, but the compiler needs to know whether this is a type template argument or a non-type template argument. So there is a rule saying that such ambiguities are always resolved in favor of a type.
If is_callable was a function template instead, there would be no ambiguity, because then is_callable<Lambda> is not a type and therefore is_callable<Lambda>() cannot be a function type. It must be a function call instead and therefore an expression and non-type template argument.
When you write (bool)is_callable<Lambda>() this is not valid syntax for a type and therefore there is no ambiguity. It is a non-type template argument and an expression. And is_callable<Lambda>() is a funcational notation explicit cast because is_callable<Lambbda> is a type. If is_callable was a function template instead of a class template, then it would be a function call.
My book mentions two ways for explicit specialization:
template <> void Swap<int> (int &, int &);
template <> void Swap(int &, int&);
what is the difference between both? when to use one and when to use the other? what is exactly the <> after the function name?
what is the difference between both?
There is no difference.
In the second case, you are letting the compiler perform type deduction from the signature of the specialization. Therefore, both forms declare a specialization of Swap<T>() for T = int.
when to use one and when to use the other?
At your discretion, when one form or the other meets your requirements in terms of readability or ease of maintenance.
what is exactly the <> after the function name?
When it comes after the function name, it is the syntax for specifying template arguments:
template<typename T = double, typename U = char>
void foo();
foo<int, bool>(); // Specifies explicit template arguments
foo<>(); // Use default template arguments
foo(); // Same as above, allowed for *function* templates only
When it comes after the template keyword, it is the syntax for introducing a (class or function) template specialization.
The first example is the real way to explicitly specialize a template, the second example is just a shortcut for the first way since the compiler can deduced the type itself from the function signature. The result is the same, there is no real difference.
The <>is used to give the template parameter to a templated structure, in this case the template parameter is the type of the manipulated data and the specialization is for the type int.
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 templated 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.
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.
Learning C++, came upon function templates. The chapter mentioned template specialization.
template <> void foo<int>(int);
void foo( int );
Why specialize when you can use the second? I thought templates were suppose to generalize. What's the point of specializing a function for a specific data type when you can just use a regular function?
Obviously, template specialization exists for a reason. When should it be used? I read Sutter's "Why not Specialize..." article but I need more of a layman's version since I'm just learning this stuff.
The main difference is that in the first case you are providing the compiler with an implementation for the particular type, while in the second you are providing an unrelated non-templated function.
If you always let the compiler infer the types, non-templated functions will be preferred by the compiler over a template, and the compiler will call the free function instead of the template, so providing a non-templated function that matches the arguments will have the same effect of specializations in most cases.
On the other hand, if at any place you provide the template argument (instead of letting the compiler infer), then it will just call the generic template and probably produce unexpected results:
template <typename T> void f(T) {
std::cout << "generic" << std::endl;
}
void f(int) {
std::cout << "f(int)" << std::endl;
}
int main() {
int x = 0;
double d = 0.0;
f(d); // generic
f(x); // f(int)
f<int>(x); // generic !! maybe not what you want
f<int>(d); // generic (same as above)
}
If you had provided an specialization for int of the template, the last two calls would call that specialization and not the generic template.
I personally can see no benefit from specializing a function template. Overloading it by either a different function template or a non-template function is arguably superior because its handling is more intuitive and it's overall more powerful (effectively by overloading the template, you have a partial specialization of the template, even though technically it's called partial ordering).
Herb Sutter has written an article Why not specialize function templates? where he discourages specializing function templates in favour of either overloading them or writing them so that they just forward to a class template's static function and specializing the class template instead.
You can use specialization when you know for a specific class the generic method could be efficient.
template<typename T>
void MySwap(T& lhs, T& rhs)
{
T tmp(lhs);
lhs = rhs;
rhs = tmp;
}
Now for vectors my swap will work, but is not very effecient. But I also know that std::vector implements its own swap() method.
template<>
void MySwap(std::vector<int>& lhs,std::vector<int>& rhs)
{
lhs.swap(rhs);
}
Please don;t compare to std::swap which is a lot more complex and better written. This is just an example to show that a generic version of MySwap() will work but is may not always be efficient. As a result I have shown how it can be made more efficient with a very specific template specialization.
We can also of course use overloading to achieve the same effect.
void MySwap(std::vector<int>& lhs,std::vector<int>& rhs)
{
lhs.swap(rhs);
}
So the question if why use template specialization (if one can use overloading). Why indeed. A non template function will always be chosen over a template function. So template specialization rules are not even invoked (which makes life a lot simpler as those rules are bizarre if you are not a lawyer as well as a computer programmer). So let me thing a second. No can't think of a good reason.
I find it very important. You can use this as you would use a virtual method. There would be no point in virtual methods unless some of them were specialized. I have used it a lot to differentiate between simple types (int,short,float) and objects, object pointers and object references.
An example would be serialize/unserialize methods that would handle objects by calling the objects serialize/unserialize method, while simple types should be written directly to a stream.
One case for template specialization which is not possible with overloading is for template meta-programming. The following is real code from a library that provides some of it services at compile time.
namespace internal{namespace os{
template <class Os> std::ostream& get();
struct stdout{};
struct stderr{};
template <> inline std::ostream& get<stdout>() { return std::cout; }
template <> inline std::ostream& get<stderr>() { return std::cerr; }
}}
// define a specialization for os::get()
#define DEFINE_FILE(ofs_name,filename)\
namespace internal{namespace os{ \
struct ofs_name{ \
std::ofstream ofs; \
ofs_name(){ ofs.open(filename);} \
~ofs_name(){ ofs.close(); delete this; } \
}; \
template <> inline std::ostream& get<ofs_name>(){ return (new ofs_name())->ofs; } \
}} \
using internal::os::ofs_name;
Multiple overloads on the same name do similar things. Specializations do the exact same thing, but on different types. Overloads have the same name, but may be defined in different scopes. A template is declared in only one scope, and the location of a specialization declaration is insignificant (although it must be at the scope of the enclosing namespace).
For example, if you extend std::swap to support your type, you must do so by specialization, because the function is named std::swap, not simply swap, and the functions in <algorithm> would be quite right to specifically call it as ::std::swap( a, b );. Likewise for any name that might be aliased across namespaces: calling a function may get "harder" once you qualify the name.
The scoping issue is confused further by argument-dependent lookup. Often an overload may be found because it is defined in proximity to the type of one of its arguments. (For example, as a static member function.) This is completely different from how the template specialization would be found, which is by simply looking up the template name, and then looking up the explicit specialization once the template has been chosen as the target of the call.
The rules of ADL are the most confusing part of the standard, so I prefer explicit specialization on the priciple of avoiding reliance on it.