Partial specialization of variadic template member function - c++

I'm struggling with specializations of member functions when they are templated using variadic template.
The following example specializes a whole class and it works fine:
template<typename... Args>
class C;
template<class T, typename... Args>
class C<T, Args...> { };
template<>
class C<> { };
int main() {
C<int, double> c{};
}
The following one does not, even though the idea behind it is exactly the same of the one above:
class F {
template<typename... Args>
void f();
};
template<class T, typename... Args>
void F::f<T, Args...>() { }
int main() {
}
I'm getting the following error and I don't understand what it's due to:
main.cpp:7:23: error: non-type partial specialization ‘f<T, Args ...>’ is not allowed
void F::f<T, Args...>() { }
^
main.cpp:7:6: error: prototype for ‘void F::f()’ does not match any in class ‘F’
void F::f<T, Args...>() { }
^
main.cpp:3:10: error: candidate is: template<class ... Args> void F::f()
void f();
^
Is there some constraints I'm not aware of when specializing function template?
G++ version is: g++ (Debian 5.2.1-23) 5.2.1 20151028
EDIT
By the way, the actual problem I'm getting from the real code is:
non-class, non-variable partial specialization ‘executeCommand<T, Args ...>’ is not allowed
Anyway, the reduced example is similar to the real one. I hope the errors are not completely unrelated.

You cannot partially specialize function templates; only explicit specialization is allowed.
You can get pretty much the same effect using overloading, especially if you use concepts such as tag dispatching.

Related

Pattern matching with variadic templates and default argument

I'm trying to add a default "hidden" setting into a templated class:
template<bool DebugMode=false, typename... Args>
struct A
{
A() {};
};
int main()
{
A<double, double> a;
}
which fails when compile with g++ 8.3.1 and C++17:
error: type/value mismatch at argument 1 in template parameter list for ‘template<bool DebugMode, class ... Args> struct A’
note: expected a constant of type ‘bool’, got ‘double’
Yet I don't understand why g++ can't do any pattern matching in template arguments. Will it be fixed a newer C++ version ?
It's basically the same as with default function arguments: You can only omit parameters from the right. And I don't expect this to change, also because what you want to do can be achieved by adding a layer of indirection:
template<bool DebugMode=false>
struct Wrap {
template <typename ...T> struct A {};
};
template <typename...T> using A = Wrap<>::A<T...>;
int main() {
A<double, double> a;
}
Alternatively:
template <bool DebugMode=false,typename ...T>
struct A_impl {};
template <typename...T>
using A = A_impl<false,T...>;
Though here the default false cannot be really used, for the using you still have to specify it.

How to deduce type of `T` from a pointer to member function?

I have a template, more or less like this:
template<typename T,void (T::*F)()>
struct Foo{
/* ... do some stuff with the member function pointer ...*/
//... e.g.
T foo(){
T t;
t.*F;
return t;
};
it works, but I dont like the way I have to instantiate it:
Foo<SomeVeryLongClassName,&SomeVeryLongClassName::AnEvenLongerMemberFunctionName> f;
Is there some way I can make the template deduce T?
I was thinking of a template method that I could call like this:
getFoo(&SomeVeryLongClassName::AnEvenLongerMemberFunctionName);
or, as I will mainly use Foo inside T, that would be just
getFoo(AnEvenLongerMemberFunctionName);
I tried this
#include <iostream>
template <typename T,void (T::*MEMFUN)()>
struct Foo{};
template <typename T,void (T::*MEMFUN)()>
Foo<typename T,typename MEMFUN> getFoo(MEMFUN f){
return Foo<typename T,typename MEMFUN>();
}
struct Bar { void test(){ std::cout << "MUH" << std::endl;} };
int main (){ getFoo(&Bar::test); }
The error messages are actually quite clear, but I dont understand them at all...
templateExample.cpp:9:28: error: wrong number of template arguments (1, should be 2)
Foo<typename T,typename MEMFUN>
^
templateExample.cpp:4:8: error: provided for ‘template<class T, void (T::* MEMFUN)()> struct Foo’
struct Foo{
^
templateExample.cpp:10:7: error: invalid type in declaration before ‘(’ token
getFoo(MEMFUN f){
^
templateExample.cpp:10:7: error: template declaration of ‘int getFoo’
templateExample.cpp:10:15: error: expected ‘)’ before ‘f’
getFoo(MEMFUN f){
^
templateExample.cpp: In function ‘int main()’:
templateExample.cpp:20:20: error: ‘getFoo’ was not declared in this scope
getFoo(&Bar::test);
...why "wrong number of template arguments (1, should be 2)" ?
How can I help the compiler to deduce T when instantiating a Foo ?
Is it possible with only pre-C++11?
PS: this is very close to being a dupe, but I really need to know the type of T and not just call the member function (e.g. I need to create an instance).
In C++17 we have non-type template parameters with deduced types:
template <auto> struct Foo;
template <typename T, void (T::*MF)()> struct Foo<MF> {
// ...
};
Usage: Foo<&X::f>
You can also directly use template <auto X> and either keep using auto inside your template or use decltype(X) to get at the type of the non-type parameter.
Prior to C++17, you could try to perform deduction via some contortions involving helper class templates with member function templates and decltype.
The gory details:
If you define a function template template <typename T, void(T::*MF)()> Foo<T, MF> f(MF);, where Foo is your old-style class template (like template <typename T, void (T::*MF)()> class Foo;), then you can use decltype(f(&X::h)) to deduce the desired type Foo<X, &X::h> without having to repeat X. The price is that you either need to say decltype everywhere, or you wrap that in a macro.

Parameter pack must be at the end of the parameter list... When and why?

I don't get the reason for which a parameter pack must be at the end of the parameter list if the latter is bound to a class, while the constraint is relaxed if the parameter list is part of a member method declaration.
In other terms, this one compiles:
class C {
template<typename T, typename... Args, typename S>
void fn() { }
};
The following one does not:
template<typename T, typename... Args, typename S>
class C { };
Why is the first case considered right and the second one is not?
I mean, if it's legal syntax, shouldn't it be in both the cases?
To be clear, the real problem is that I was defining a class similar to the following one:
template<typename T, typename... Args, typename Allocator>
class C { };
Having the allocator type as the last type would be appreciated, but I can work around it somehow (anyway, if you have a suggestion it's appreciated, maybe yours are far more elegant than mine!!).
That said, I got the error:
parameter pack 'Args' must be at the end of the template parameter list
So, I was just curious to fully understand why it's accepted in some cases, but it is not in some others.
Here is a similar question, but it simply explains how to solve the problem and that was quite clear to me.
It is valid for function templates but only when argument deduction can help the compiler resolve the template parameters, as it stands your function template example is virtually useless because
template<typename T, typename... Args, typename S> void fn() { }
int main() { fn<int, int, int>(); }
test.cpp: In function 'int main()':
test.cpp:2:32: error: no matching function for call to 'fn()'
int main() { fn<int, int, int>(); }
^
test.cpp:1:57: note: candidate: template<class T, class ... Args, class S> void fn()
template<typename T, typename... Args, typename S> void fn() { }
^
test.cpp:1:57: note: template argument deduction/substitution failed:
test.cpp:2:32: note: couldn't deduce template parameter 'S'
int main() { fn<int, int, int>(); }
the compiler has no way of determining which template parameters belong to the parameter pack, and which to S. In fact as #T.C. points out it should actually be a syntax error because a function template defined in this manner cannot ever be instantiated.
A more useful function template would be something like
template<typename T, typename... Args, typename S> void fn(S s) { }
as now the compiler is able to unambiguously match the function parameter s with the template type S, with the side effect that S will always be deduced - all explicit template parameters after the first will belong to Args.
None of this works for (primary) class templates, parameters aren't deduced and it's expressly forbidden:
From draft n4567
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4567.pdf
[temp.param] / 11
[...]If a template-parameter of a primary class template or alias
template is a template parameter pack, it shall be the last
template-parameter.[...]
(if they were deduced it would be ambiguous as in the function template example).
The first one is not right. The compiler is just buggy and failed to diagnose it. [temp.param]/11:
A template parameter pack of a function template shall not be followed
by another template parameter unless that template parameter can be
deduced from the parameter-type-list of the function template or has a
default argument (14.8.2).
If the function type T(Args...) is meaningful to the end-user, one way to fix this would be to use a partial specialization instead:
template<class F, class Alloc> class C; //undefined
template<class T, class... Args, class Alloc>
class C<T(Args...), Alloc> {
// implementation
};
Depending on the actual requirements, type-erasing the allocator might also be worth considering.

Variadic template constructor speciliazation in template class

I want to be able to specialize the ctor of a class the following way:
template<typename T>
class Foo {
public:
template<typename... Ts>
Foo(Ts... & args) {
// ...
}
template<>
Foo(int i) {
// ...
}
};
I get the following error:
error: explicit specialization in non-namespace scope ‘class Foo’
If I try to move the specialization outside the class, like this:
template<typename T>
class Foo {
public:
template<typename... Ts>
Foo(Ts &... args) {
// ...
}
};
template<typename T>
template<int>
Foo<T>::Foo(int i) {
// ...
}
I get the following errors:
error: prototype for ‘Foo::Foo(int)’ does not match any in class
‘Foo’
error: candidate is: template template
Foo::Foo(Ts& ...)
How do I do this correctly?
You can just overload the constructor instead:
template<typename T>
class Foo {
public:
template<typename... Ts>
Foo(Ts&... args) {
// ...
}
// template<> <- REMOVE THIS
Foo(int i) {
// ...
}
};
Overload resolution will prefer the non-template overload so doing Foo<MyType> f(1234); would choose Foo<MyType>::Foo(int);.
LIVE EXAMPLE (I've modified the variadic to be const for it to accept temporaries for the sake of the example).
Note that the position of the type modifier in your variadic function is wrong. It should be with the type, on the left side of ...:
Foo(Ts&... args)
member function and by extension constructors are not specialize-able without specializing the outer template completely.
Just write the ctor with an int not template will works here.
14.7.3p18: "In an explicit specialization declaration for a member of a class template or a member template that appears in namespace scope,
the member template and some of its enclosing class templates may
remain unspecialized, except that the declaration shall not explicitly
specialize a class member template if its enclosing class templates
are not explicitly specialized as well."

GCC claims a friend function to be overloaded, ambiguous call, clang compiles

template <typename T>
class rp {
};
template <template <typename> class P>
struct b {
template <class, template <typename> class FriendP>
friend void f(b<FriendP> from);
};
template <class, template <typename> class P>
void f(b<P> from) {
}
int main() {
b<rp> v;
f<int>(v);
return 0;
}
Clang 3.3 (svn) compiles fine, while GCC 4.8 rejects it:
main.cpp: In function 'int main()':
main.cpp:17:10: error: call of overloaded 'f(b<rp>&)' is ambiguous
f<int>(v);
^
main.cpp:17:10: note: candidates are:
main.cpp:12:6: note: void f(b<P>) [with <template-parameter-1-1> = int; P = rp]
void f(b<P> from) {
^
main.cpp:8:17: note: void f(b<FriendP>) [with <template-parameter-2-1> = int; FriendP = rp; P = rp]
friend void f(b<FriendP> from);
^
I wonder why GCC claims f to be overloaded. So I guess it's a GCC bug.
Which compiler is right?
Friend injection does no longer exist in the c++ standard, see this for informations about this. However, since the friend function declared inside struct b "acts" on a parameter of type "b", the function is found via ADL (argument-dependant lookup). When this happens 2 different functions having the same signature are declared, and the compiler complains.
This is probably what you meant:
template <template <typename> class P>
struct b {
template <class, template <typename> class FriendP>
friend void f(b<FriendP> from){};
};
but don't use this in real code as it is, since "duplicate function" problems can, as you see, easily arise (proper use of namespaces can be of help with this respect).
The code can be tested here
A good reference for the use (as well as a good real-life example of why they are needed) of template friend functions can be found in item 46 of Effective c++