Pattern matching with variadic templates and default argument - c++

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.

Related

C++: How to partially deduce template arguments from make_shared

In order to circumvent the restriction on partially supplied explicit template arguments, I embed the struct from which I want to deduce the class template parameters (Internal) into a second struct (Container).
I would like to enable the user of the code to create e.g. shared pointers of the resulting type. By writing my own create function within the struct, this works just fine.
#include <memory>
/// Container that is used in order to partially specify template arguments
template <int A> struct Container {
/// Contained type, of which the template arguments are deduced.
template <int B> struct Internal {
explicit Internal(std::integral_constant<int, B> fu) { (void)fu; }
};
/// Helper function
template <int C>
[[nodiscard]] static auto create(std::integral_constant<int, C> t) noexcept {
return std::make_shared<Container<A>::Internal<C>>(t);
}
};
int main() {
Container<1>::Internal works{std::integral_constant<int, 8>{}};
auto const worksAswell = Container<1>::create(std::integral_constant<int, 8>{});
}
But when I try to use make_shared directly, it fails. I would like to enable the user to use e.g. the std::make_shared function.
int main() {
auto const fails = std::make_shared<Container<1>::Internal>(std::integral_constant<int, 8>{});
}
From what I understand, this fails because I cannot partially specify template arguments, and I am unable to deduce them from the make_shared function if I don't want to specify all template parameters.
main.cc: In function ‘int main()’:
main.cc:21:74: error: no matching function for call to ‘make_shared<1>(std::integral_constant<int, 8>)’
21 | auto const fails = std::make_shared<1>(std::integral_constant<int, 8>{});
| ^
In file included from /usr/include/c++/9.2.0/memory:81,
from /home/juli/main9.cc:1:
/usr/include/c++/9.2.0/bits/shared_ptr.h:714:5: note: candidate: ‘template<class _Tp, class ... _Args> std::shared_ptr<_Tp> std::make_shared(_Args&& ...)’
714 | make_shared(_Args&&... __args)
| ^~~~~~~~~~~
/usr/include/c++/9.2.0/bits/shared_ptr.h:714:5: note: template argument deduction/substitution failed:
Is it possible to enable generator functions like std::make_shared to partially deduce template arguments like that? The entire code can be found here.
If you create your own make_shared that accepts a template template parameter we can use decltype to deduce the resulting type and pass that on to std::make_shared.
#include <memory>
#include <type_traits>
/// Container that is used in order to partially specify template arguments
template <int A> struct Container {
/// Contained type, of which the template arguments are deduced.
template <int B> struct Internal {
explicit Internal(std::integral_constant<int, B> fu) { (void)fu; }
};
};
template <template <int> typename partial, typename... Args>
auto make_shared(Args&&... args) {
using target_type = std::remove_pointer_t<decltype(new partial{std::declval<Args>()...})>;
return std::make_shared<target_type>(std::forward<Args>(args)...);
}
using std::make_shared;
int main() {
auto const fails = make_shared<Container<1>::Internal>(std::integral_constant<int, 8>{});
static_assert(std::is_same_v<const std::shared_ptr<Container<1>::Internal<8>>, decltype(fails)>);
}
The only issue here is that our make_shared needs to know the template signature of the expected target.
On the positive side we can add several overloads for different template signatures and we can use one parameter pack.

g++ and clang++ different behaviour with non-type argument in struct/class specialization

I try to understand meaning and implications of 14.5.5/8 of the C++11 standard (idem in C++14 and, I suppose, in C++17)
The type of a template parameter corresponding to a specialized non-type argument shall not be dependent on a parameter of the specialization.
and, as usual, to understand who's correct between g++ and clang++.
The standard show the following example
template <class T, T t> struct C {};
template <class T> struct C<T, 1>; // error
and both g++ and clang++ give error.
So far, so good.
Let's complicate a little the example adding a type
template <typename, typename T, T>
struct foo { };
template <typename T>
struct foo<T, int, 1> { }; // compile
template <typename T>
struct foo<T, T, 1> { }; // error
Both g++ and clang++ compile the first partial specialization (the type of 1, int, isn't a parameter of the specialization) and give error with the second one (the type of 1 is T, a parameter of the specialization)
So far, so good.
Let's introduce a template struct bar with an internal type that doesn't depend from the template parameter
template <typename>
struct bar
{ using type = int; };
and the following program
template <typename>
struct bar { using type = int; };
template <typename, typename T, T>
struct foo { };
template <typename T>
struct foo<T, typename bar<T>::type, 1> { };
int main ()
{ }
it's compiled without error by g++ (tried in wandbox with 4.9.3, 5.5.0, 7.2.0 and head 8.0.0; with c++11, c++14 and, when available, c++17) but clang++ (3.9.1, 4.0.1, 5.0.0, head 6.0.0; c++11, c++14, c++17) give the following error
prog.cc:11:38: error: non-type template argument specializes a template parameter with dependent type 'T'
struct foo<T, typename bar<T>::type, 1> { };
^
prog.cc:7:34: note: template parameter is declared here
template <typename, typename T, T>
~^
As usual: who's right?
clang++, that consider 1 dependent on T (when typename bar<T>::type is fixed as int) or g++ that doesn't relieve this dependencies?
For completeness I have to say that changing bar as follows
template <typename T>
struct bar { using type = T; };
so making the bar<T>::type dependant on T, nothing change: g++ compile without error, and clang++ give the same error.
Look at it from the compiler's point of view.
template <class T, T t> struct C {};
template <class T> struct C<T, 1>; // error
For the specialization, the compiler doesn't know if T can indeed have a value of 1, and so the specialization is invalid.
For
template <typename T>
struct foo<T, typename bar<T>::type, 1> { };
Who's saying that type is always int? You might think that it is obvious, but I could introduce a specialization of bar for one specific T so that type is a std::string:
template<>
struct bar<const volatile int> { using type = std::string };
Basically, your statement "when typename bar<T>::type is fixed as int" is wrong, it is not fixed.
Now what? The standard here says the same thing as for your first example, the specialization is ill-formed, because as your quote correctly states, the type of the non-type parameter depends on another (templated) type of the specialization, namely T, which is unknown. In that regard, clang is right, and gcc is wrong.

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.

Compiler errors on partial template speciailzation (c++)

I am trying to do a simple partial template specialization, but I get errors on g++4.4.7, g++4.8.5, clang++3.8.0. Whenever I mention compiler(s) error, I mean the output of all of these, as they always agree.
I am using C++03, compiling without any option.
The code:
#include <iostream>
template <typename T, typename X, typename G>
struct A {};
template <typename T, typename X>
struct A<T, X, void> { A() : n(1) {} X n; T b; };
template <typename X>
struct A<X, void, void> { A() : n(2) {} X n; };
int main() {
A<int, float> one;
A<int> two;
std::cout << one.n << " | " << two.n << "\n";
return 0;
}
Question 1: This code fails to compile. The compilers say that A<int, float> and A<int> are wrong as A requires 3 templates parameters. Why?
If I change the original declaration to
template <typename T, typename X = void, typename G = void>
struct A {};
The code compiles and the output is: 1 | 2.
What happens is that the compiler in a first step matches one and two type to the not specialized A, but then it correctly decides to use the code of the partially specialized class one would expect it to use. But it should not need the defaults.
I then decide to change the last partial specialization switching the first and second parameter:
template <typename X>
struct A<void, X, void> { A() : n(2) {} X n; };
I would expect this to change nothing, but the compilers disagree. The clearest output between the 3 is here reported:
a.cpp:7:40: error: field has incomplete type 'void'
struct A<T, X, void> { A() : n(1) {} X n; T b; };
^
a.cpp:14:10: note: in instantiation of template class 'A<int, void, void>' requested here
A<int> two;
^
1 error generated.
Question 2: Why are the compilers considering the two variable an instance of the partial specialization of A that specializes only one argument?
Note that is the "2nd matching", because if I only use 1 default template argument, the compiler will go back to complaining about the fact that 3 template parameters are needed.
Thanks.
Question 1: This code fails to compile. The compilers say that A<int, float> and A<int> are wrong as A requires 3 templates parameters. Why?
Because A requires 3 template parameters. You declared A as:
template <typename T, typename X, typename G>
struct A {};
There is no two- or one-template parameter version of A. There are versions specialized on some of the types being void, but that's still a parameter - not an absence of parameter.
When you add the defaults, then A<int, float> evaluates as A<int, float, void>, which is a valid instantiation - and picks the specialization which sets n to 1.
You're misunderstanding how specialization works. Specialization doesn't change the number of template parameters. It's just a way of adding special functionality depending on what the template parameters end up being.
Question 2: Why are the compilers considering the two variable an instance of the partial specialization of A that specializes only one argument?
We have three choices
template <T, X, G> struct A; // the primary
template <T, X, void> struct A; // (1)
template <void, X, void> struct A; // (2)
When we instantiate A<int>, that is the same as A<int, void, void> when we add in the default parameters. That does not match (2) - because that one requires the first parameter to be void and yours is int. (1) is a better match than the primary since it's more specialized. But then, (1) has a member of type X and in this case X is deduced as void (from the default parameter), and that's not allowed.

Partial specialization of variadic template member function

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.