Why default argument cannot be specified for an explicit template specialization? - c++

The below code couldn't pass the compilation, what's the consideration for this compiler error?
template<class T> void f(T t) {};
template<> void f<char>(char c = 'a') {}
Error message: Default arguments are not allowed on an explicit specialization of a function template

I think that the rationale behind this error is due to the fact that the default arguments in the function template apply to its specialization as well and you are not allowed to define the default argument more than once in C++.
Consider the following:
#include <iostream>
template<class T> void f(T t = 'a') {}
template<> void f<char>(char c)
{
std::cout << c << std::endl;
}
int main(int argc, char **argv)
{
f<char>();
}
This will print a meaning that specialization is called with the default argument defined in the main template.
If you need a different default argument for each specialization you can use the approach illustrated below:
#include <iostream>
template<class T>
struct default_arg
{
static T get() { return T(); }
};
template<class T> void f(T t = default_arg<T>::get()) {}
template<>
struct default_arg<char>
{
static char get() { return 'a'; }
};
template<> void f<char>(char c)
{
std::cout << c << std::endl;
}
int main(int argc, char **argv)
{
f<char>();
}

C++98 §12.7/21 "Default function arguments shall not be specified in ... the explicit specialization of a function template".
Regarding rationale I think it has to do with a call always being resolved against the primary template. A call that leaves out an argument required by the primary template, couldn't be resolved wihtout changing the lookup rules.

The particular template instance used is decided by the type of the function argument. Thus, in this case, the explicit specialization is selected by the providing a char argument; it is only at this point that the default argument would come into play, where it is now redundant.
It only makes sense to provide default arguments on the template declaration itself. The disadvantage is that you have to specify the appropriate specialization yourself, namely f<char>(), which removes some of the advantages in using a default argument in the first place.
To achieve the behavior that, I believe, you want, use the following:
template<class T> void f(T t) {}
template<> void f<char>(char c) {}
void f() { f('a'); }

Related

Member function template to call a funcion on a data member with arbitrary arguments

I'm working on a C++11 code base and wondering how I can call any function on a member type passing arbitrary arguments. Note that since I'm using C++11 I can't use something like std::invoke.
I started creating a function template in the Outer class, but my initial try gives me a compile error.
#include <iostream>
#include <utility>
#include <type_traits>
struct Inner {
void bar(int x) {
std::cout << "Called: x=" << x << std::endl;
}
};
struct Outer {
explicit Outer(Inner *i) : b{i} {}
void foo(int) {}
Inner* b;
template <typename Func, typename ... Args>
void CallInner(Func&& f, Args&& ... args) {
b->f(std::forward<Args>(args)...);
}
};
int main() {
Inner inner{};
Outer outer(&inner);
outer.CallInner(&Inner::bar, 5);
}
Try it out yourself
Again, I would like to keep the signature of the function CallInner unchanged from the above sample code.
Since f is a pointer a member function it needs to be dereferenced first before being called:
(b->*f)(std::forward<Args>(args)...);
You don't have much choice with regards to changing the signature, because at least one additional template is required.
The correct syntax is a little bit more complicated:
struct Outer {
explicit Outer(Inner *i) : b{i} {}
void foo(int) {}
Inner* b;
template <typename Ret, typename ...FuncArgs, typename ... Args>
void CallInner(Ret (Inner::*f)(FuncArgs...), Args&& ... args) {
(b->*f)(std::forward<Args>(args)...);
}
};
The first parameter to CallInner must be a method pointer, and, in a template context, it needs to be templated not just by a set of variadic template parameters, FuncArgs, but also its return type, Ret. Then you also need a second set of variadic template parameters for the forwarding references of the arguments you're forwarding (which may not necessarily be the same as FuncArgs, hence the need for a separate set of variadic template types).

Why these C++ cases instantiate different templates

I am trying to write some functionality where I need to save different functions and later extract their arguments' types. So I'm using the function signature as template parameter. But I get somewhat unexpected results.
Here's the code:
#include <functional>
#include <iostream>
template <class T>
struct foo
{
foo()
{
std::cout << "class T" << std::endl;
}
};
template <class Ret, class Arg>
struct foo<Ret(Arg)>
{
foo()
{
std::cout << "Ret(Arg)" << std::endl;
}
};
template <class T>
void save(std::function<T>)
{
new foo<T>();
}
int main(int argc, char* argv[])
{
std::function<void(void)> someFoo;
save(someFoo);
return 0;
}
So if the variable someFoo is a function with type void(void), it instantiates the first template, foo<T>. But if I change it to void(int), than I get the desired specialized template instantiated. Why is that?
In C++, having a void argument is actually the same as having no argument at all (unlike in C, by the way). So it would match a specialization for Ret(), but it can't match a specialization for Ret(Arg).
void(void) is the exact same as void() - the second void is optional and makes no difference.
That's why the first template with no parameters is used.

Unified function calls for instances and primitive types using template specialization and interfaces

I'd like to call a function AsJson in a unified way irrespective of whether I'm dealing with an instance or a primitive type, or anything else.
I thought I could define an abstract base class which classes could inherit, and then define a template function that calls the AsJson member function when the template is specialized to appropriate classes. For other types, they could just specialize the template function.
Something like this:
#include <iostream>
class IInstrumented {
public:
virtual void AsJson() const = 0;
};
template <typename T>
void AsJson(const T&);
template <typename T>
void AsJson(const IInstrumented& instrumented) {
instrumented.AsJson();
}
class Foo : public IInstrumented {
public:
void AsJson() const override { std::cout << "A Foo!" << std::endl; }
};
template <>
void AsJson(const int& x) {
std::cout << "An integer!" << std::endl;
}
int main() {
Foo foo;
AsJson(foo);
int x = 3;
AsJson(x);
}
Unfortunately, this results in the following linker error:
special.cpp:(.text+0x56): undefined reference to `void AsJson<Foo>(Foo const&)'
Is this approach workable as is? Is the fix something relatively minor, or is an entirely different approach warranted?
Although there is an accepted answer, I thought I would point out why you had the error in the first place.
When compiling
AsJson(foo);
the compiler is looking for this template instantiation:
template <>
void AsJson(const Foo&);
which is not defined(undefined reference error) because
template <typename T>
void AsJson(const T&);
has no implementation. It is not using this template specialization:
template <>
void AsJson(const IInstrumented& instrumented) {
instrumented.AsJson();
}
because it is not the best candidate while deducting type. By changing the code to:
AsJson<IInstrumented>(foo);
You then explicitly tell the compiler which template specialization you want to use. Previous answer assume all types will inherits from IInstrumented which might not be the case hence why the static_assert checking for type was added.
By providing a default implementation, you can avoid the necessity to inherits from IInstrumentable. Adding an assert in there might help catching serializing unknown types.
You should change
template <typename T>
void AsJson(const IInstrumented& instrumented) {
instrumented.AsJson();
}
to
template <typename T>
void AsJson(const T& instrumented) {
instrumented.AsJson();
}
And then:
$ ./bla
A Foo!
An integer!
Now if you want to ensure that T is derived from IInstrumented. You should add (c++11 only) :
template <typename T>
void AsJson(const T& instrumented) {
static_assert(std::is_base_of<IInstrumented, T>::value,
"T must be a descendant of IInstrumented"
);
instrumented.AsJson();
}
Then with
class Bar {
public:
void AsJson() { std::cout << "A Foo!" << std::endl; }
};
The following code:
Bar bar;
AsJson(bar);
raises:
bla.cpp: In instantiation of ‘void AsJson(const T&) [with T = Bar]’:
bla.cpp:38:13: required from here
bla.cpp:13:3: error: static assertion failed: T must be a descendant of IInstrumented
static_assert(std::is_base_of<IInstrumented, T>::value,
See also How to ensure that the template parameter is a subtype of a desired type?

overloading function and inheritance

I am trying to overload some template function to perform specific action if I call it using a given class MyClass or any derived class MyClassDer. Here is the code:
#include <iostream>
struct MyClass {
virtual void debug () const {
std::cerr << "MyClass" << std::endl;
};
};
struct MyClassDer : public MyClass {
virtual void debug () const {
std::cerr << "MyClassDer" << std::endl;
};
};
template <typename T> void func (const T& t) {
std::cerr << "func template" << std::endl;
}
void func (const MyClass& myClass) {
std::cerr << "func overloaded" << std::endl;
myClass.debug ();
}
int main(int argc, char **argv) {
func (1);
MyClass myClass;
func (myClass);
MyClassDer myClassDer;
func (myClassDer);
}
The output is:
func template
func overloaded
MyClass
func template
func (myClassDer) calls the template function instead of void func (const MyClass& myClass). What can I do to get the expected behavior?
Thanks
This is just how overload resolution works. When lookup completes it finds both the template and the function. The template types are then deduced and overload resolution starts. In the case of an argument of type MyClass the two candiates are:
void func<MyClass>(MyClass const&);
void func(MyClass const&);
Which are equally good matches for the arguments, but the second being a non-template is preferred. In the case of MyClassDer:
void func<MyClassDer>(MyClassDer const&);
void func(MyClass const&);
In this case the first is a better candidate than the second one, as the second one requires a derived-to-base conversion and that is picked up.
There are different approaches to direct dispatch to hit your code. The simplest is just coercing the type of the argument to be MyClass and thus fallback to the original case:
func(static_cast<MyClass&>(myClassDer));
While simple, this needs to be done everywhere and if you forget in just one place, the wrong thing will be called. The rest of the solutions are complex and you might want to consider whether it would not be better to just provide different function names.
One of the options is using SFINAE to disable the template when the type is derived from MyClass:
template <typename T>
typename std::enable_if<!std::is_base_of<MyClass,MyClassDer>::value>::type
func(T const & t) { ... }
In this case, after lookup, the compiler will perform type deduction, and it will deduce T to be MyClassDer, it will then evaluate the return type of the function (SFINAE could also be applied to another template or function argument). The is_base_of will yield false and the enable_if won't have a nested type. The function declaration will be ill-formed and the compiler will drop it, leaving the resolution set with a single candidate, the non-template overload.
Another option would be providing a single template interface, and dispatching internally to either a template or the overload (by a different name) using tag-dispatch. The idea is similar, you evaluate the trait inside the template and call a function with a type generated from that evaluation.
template <typename T>
void func_impl(T const&, std::false_type) {...}
void func_impl(MyClass const&, std::true_type) {...}
template <typename T>
void func(T const &x) {
func_impl(x,std::is_base_of<MyClass,MyClassDer>::type());
}
There are other alternatives, but those are two common ones and the rest are mainly based on the same principles.
Again, consider whether the problem is worth the complexity of the solution. Unless the call to func is itself done inside generic code, a simple change of the function name will solve the problem without unnecessarily adding complexity that you or the other maintainers might have problems maintaining.
For why your code didn't work: see #David's excellent explanation. To get it to work, you can use SFINAE ("Substition Failure is not an Errro) by adding a hidden template parameter Requires (the name is for documentation purposes only)
template <
typename T, typename Requires = typename
std::enable_if<!std::is_base_of<MyClass, T>::value, void>::type
>
void func (const T& t) {
std::cerr << "func template" << std::endl;
}
This will disable this template for overload resolution whenever T is equal to or derived from MyClass, and will select the regular function instead (for which Derived-to-Base conversions will be performed, in contrast to template argument deduction, which considers exact matches only). You can obviously play around with this and add several overloads with non-overlapping conditions inside the std::enable_if to have a fine-grained selection of function overloads that will be considered. But be careful, SFINAE is subtle!
Live Example.
Note: I wrote my SFINAE with C++11 syntax, using a default template parameter for function templates. In C++98 you need to add either a regular default parameter or modify the return type.
You can use SFINAE:
#include <type_traits>
template <typename T>
void func (const T& t, typename std::enable_if<!std::is_base_of<MyClass, T>::value>::type * = nullptr) {
std::cout << "func template" << std::endl;
}
template <
typename T
, typename = typename std::enable_if<std::is_base_of<MyClass, T>::value>::type
>
void func (const T& t) {
std::cout << "func overloaded" << std::endl;
t.debug ();
}
If you don't have C++11, boost provides the same functionality.
Live example
EDIT
This should work without C++11 (using boost):
#include "boost/type_traits.hpp"
template <typename T>
void func (const T& t, typename boost::enable_if<!boost::is_base_of<MyClass, T>::value>::type * = 0) {
std::cout << "func template" << std::endl;
}
template <typename T>
void func (const T& t, typename boost::enable_if<boost::is_base_of<MyClass, T>::value>::type * = 0) {
std::cout << "func overloaded" << std::endl;
t.debug ();
}
Polymorphism occurs in run-time, but choosing an overloaded function occurs in compile-time.
So, in compile time the best overload to accept MyClassDer is
func<MyClassDer> (const MyClassDer& t)
rather than
func<MyClass> (const MyClass& t)
then compiler chooses the first.
A possibility to solve the issue is:
func(static_cast<MyClass&>(myClassDer));
You will need to use polymorphism in order to call your template function. You need a reference to your base class:
int main(int argc, char **argv) {
func (1);
MyClass myClass;
func (myClass);
MyClassDer myClassDer;
MyClass* mc = &myClassDer;
func (*mc);
}
More polymorphism examples and details here
Its because your overloaded function's signature is,
void func (const MyClass& myClass)
{
std::cerr << "func overloaded" << std::endl;
myClass.debug ();
}
i.e it wants MyClass as its parameter and you are calling it using MyClassDer. So at compile time it resolves the other overloaded function and links with that. As the other function is templated there is no problem for compiler to link with that.
So if you want to pass a MyClassDer object, you could still do it using polymorphism.
MyClass *myClassDer = new MyClassDer;
func(*myClassDer);
Just cast it to the base type:
MyClassDer myClassDer;
func(static_cast<MyClass&>(myClassDer));
MyClass *myClassDer = new MyClassDer;
func(*myClassDer);
delete myClassDer;

How to call a templated function if it exists, and something else otherwise?

I want to do something like
template <typename T>
void foo(const T& t) {
IF bar(t) would compile
bar(t);
ELSE
baz(t);
}
I thought that something using enable_if would do the job here, splitting up foo into two pieces, but I can't seem to work out the details. What's the simplest way of achieving this?
There are two lookups that are done for the name bar. One is the unqualified lookup at the definition context of foo. The other is argument dependent lookup at each instantiation context (but the result of the lookup at each instantiation context is not allowed to change behavior between two different instantiation contexts).
To get the desired behavior, you could go and define a fallback function in a fallback namespace that returns some unique type
namespace fallback {
// sizeof > 1
struct flag { char c[2]; };
flag bar(...);
}
The bar function will be called if nothing else matches because the ellipsis has worst conversion cost. Now, include that candidates into your function by a using directive of fallback, so that fallback::bar is included as candidate into the call to bar.
Now, to see whether a call to bar resolves to your function, you will call it, and check whether the return type is flag. The return type of an otherwise chosen function could be void, so you have to do some comma operator tricks to get around that.
namespace fallback {
int operator,(flag, flag);
// map everything else to void
template<typename T>
void operator,(flag, T const&);
// sizeof 1
char operator,(int, flag);
}
If our function was selected then the comma operator invocation will return a reference to int. If not or if the selected function returned void, then the invocation returns void in turn. Then the next invocation with flag as second argument will return a type that has sizeof 1 if our fallback was selected, and a sizeof greater 1 (the built-in comma operator will be used because void is in the mix) if something else was selected.
We compare the sizeof and delegate to a struct.
template<bool>
struct foo_impl;
/* bar available */
template<>
struct foo_impl<true> {
template<typename T>
static void foo(T const &t) {
bar(t);
}
};
/* bar not available */
template<>
struct foo_impl<false> {
template<typename T>
static void foo(T const&) {
std::cout << "not available, calling baz...";
}
};
template <typename T>
void foo(const T& t) {
using namespace fallback;
foo_impl<sizeof (fallback::flag(), bar(t), fallback::flag()) != 1>
::foo(t);
}
This solution is ambiguous if the existing function has an ellipsis too. But that seems to be rather unlikely. Test using the fallback:
struct C { };
int main() {
// => "not available, calling baz..."
foo(C());
}
And if a candidate is found using argument dependent lookup
struct C { };
void bar(C) {
std::cout << "called!";
}
int main() {
// => "called!"
foo(C());
}
To test unqualified lookup at definition context, let's define the following function above foo_impl and foo (put the foo_impl template above foo, so they have both the same definition context)
void bar(double d) {
std::cout << "bar(double) called!";
}
// ... foo template ...
int main() {
// => "bar(double) called!"
foo(12);
}
litb has given you a very good answer. However, I wonder whether, given more context, we couldn't come up with something that's less generic, but also less, um, elaborate?
For example, what types can be T? Anything? A few types? A very restricted set which you have control over? Some classes you design in conjunction with the function foo? Given the latter, you could simple put something like
typedef boolean<true> has_bar_func;
into the types and then switch to different foo overloads based on that:
template <typename T>
void foo_impl(const T& t, boolean<true> /*has_bar_func*/);
template <typename T>
void foo_impl(const T& t, boolean<false> /*has_bar_func*/);
template <typename T>
void foo(const T& t) {
foo_impl( t, typename T::has_bar_func() );
}
Also, can the bar/baz function have just about any signature, is there a somewhat restricted set, or is there just one valid signature? If the latter, litb's (excellent) fallback idea, in conjunction with a meta-function employing sizeof might be a bit simpler. But this I haven't explored, so it's just a thought.
I think litb's solution works, but is overly complex. The reason is that he's introducing a function fallback::bar(...) which acts as a "function of last resort", and then goes to great lengths NOT to call it. Why? It seems we have a perfect behavior for it:
namespace fallback {
template<typename T>
inline void bar(T const& t, ...)
{
baz(t);
}
}
template<typename T>
void foo(T const& t)
{
using namespace fallback;
bar(t);
}
But as I indicated in a comment to litb's original post, there are many reasons why bar(t) could fail to compile, and I'm not certain this solution handles the same cases. It certainly will fail on a private bar::bar(T t)
If you're willing to limit yourself to Visual C++, you can use the __if_exists and __if_not_exists statements.
Handy in a pinch, but platform specific.
EDIT: I spoke too soon! litb's answer shows how this can actually be done (at the possible cost of your sanity... :-P)
Unfortunately I think the general case of checking "would this compile" is out of reach of function template argument deduction + SFINAE, which is the usual trick for this stuff. I think the best you can do is to create a "backup" function template:
template <typename T>
void bar(T t) { // "Backup" bar() template
baz(t);
}
And then change foo() to simply:
template <typename T>
void foo(const T& t) {
bar(t);
}
This will work for most cases. Because the bar() template's parameter type is T, it will be deemed "less specialised" when compared with any other function or function template named bar() and will therefore cede priority to that pre-existing function or function template during overload resolution. Except that:
If the pre-existing bar() is itself a function template taking a template parameter of type T, an ambiguity will arise because neither template is more specialised than the other, and the compiler will complain.
Implicit conversions also won't work, and will lead to hard-to-diagnose problems: Suppose there is a pre-existing bar(long) but foo(123) is called. In this case, the compiler will quietly choose to instantiate the "backup" bar() template with T = int instead of performing the int->long promotion, even though the latter would have compiled and worked fine!
In short: there's no easy, complete solution, and I'm pretty sure there's not even a tricky-as-hell, complete solution. :(
//default
//////////////////////////////////////////
template <class T>
void foo(const T& t){
baz(t);
}
//specializations
//////////////////////////////////////////
template <>
void foo(const specialization_1& t){
bar(t);
}
....
template <>
void foo(const specialization_n& t){
bar(t);
}
Are you not able to use full specialisation here (or overloading) on foo. By say having the function template call bar but for certain types fully specialise it to call baz?