Cannot Pass Variable Args to Nested Variadic Template Call [duplicate] - c++

This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 6 years ago.
Compiler: TDM-GCC 5.1.0 (SJLJ Unwinding)
I'm having an issue passing variable number of type arguments to a static variadic template method call inside of a template function. I've tried every syntax variation, but it won't compile, so I can only assume I'm doing this wrong.
Here's the setup:
#include <iostream>
template <class T>
struct Foo
{
template <class...>
static void test()
{
std::cout << "Foo<T>::test<...>() called.";
}
};
template <class T, class... Args>
void bar()
{
Foo<T>::test<Args...>(); //error happens here
}
int main()
{
bar<int, int>();
}
This gives the compiler error: expected primary-expression before '...' token.
I thought pack expansions looked like Args..., but that doesn't seems to work here.
Any help is appreciated.

You need to tell the parser that dependant test is a template:
template <class T, class... Args>
void bar()
{
Foo<T>::template test<Args...>(); //error happens here
^^^^^^^^^
}
demo

Related

c++ type_traits: Why can't I call templated static methods from another template / enable_if line? [duplicate]

This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 2 years ago.
I would like to use a static method in a template parameter in my function in an enable_if expression. However, the static method is also a template, and I get compiler errors.
The error message:
$ g++ test.cpp
test.cpp:20:36: error: invalid declarator before ‘(’ token
20 | std::enable_if_t<A::method_a<param>()>
Code sample:
#include <type_traits>
struct B
{
template<int param>
static constexpr int method_a()
{
return param == 5;
}
static constexpr int method_b(int param)
{
return param == 5;
}
};
// this doesn't work
template<int param, typename A>
std::enable_if_t<A::method_a<param>()>
func_a(A& a)
{}
// this works
template<int param, typename A>
std::enable_if_t<A::method_b(param)>
func_b(A& a)
{}
int main()
{
B b;
func_b<5>(b); // this doesn't work
func_a<5>(b); // this works
return 0;
}
In func_a, the name method_a is a dependent name i.e. the meaning of method_a depends on the template type parameter A. If the name is a member template, you need to specify that with the template keyword:
template<int param, typename A>
std::enable_if_t<A::template method_a<param>()>
// ^^^^^^^^
func_a(A& a){}
Here's a demo.

Partially filled template as parameter for template template [duplicate]

This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 5 years ago.
I have a template with two template arguments (MyCollection) and another template (TCTools) expecting a template with one template argument as template argument.
I defined a "bridge" (TypedCollection) to get a template with one parameter from MyCollection and an argument for it's first parameter with the aim of passing it to the template template.
This works fine, if I use the bridge with a fixed type as argument, but calling it from yet another template with the argument of that other template will not compile.
#include <iostream>
using std::size_t;
template <class Scalar, size_t size>
struct MyCollection
{
MyCollection()
{
std::cout << "Made collection"
<< std::endl
<< " " << __PRETTY_FUNCTION__
<< std::endl;
}
};
template <class Scalar>
struct TypedCollection
{
template <size_t size>
using value = MyCollection<Scalar, size>;
};
template <template <size_t> class TC>
struct TCTools
{
static TC<10> *make_10_sized()
{
return new TC<10>();
}
};
template <class S>
void test()
{
// Will not compile
TCTools<TypedCollection<S>::value>::make_10_sized();
}
int main()
{
// works
TCTools<TypedCollection<int>::value>::make_10_sized();
test<int>();
return 0;
}
GCC gives the following note:
expected a class template, got ‘TypedCollection<S>::value’
The whole thing has left me very confused. Why is the call in test() not compiling, while the one in main() works just as expected? Is it possible to get test to work?
TCTools<TypedCollection<S>::template value>::make_10_sized()
much like typename (but confusingly different), you have to disambiguate what value is, or the compiler assumes it is a value and not a type or template.
It does this before S is substituted. In theory, a specialization of TypedCollection<S> could make value anything at all, and the compiler doesn't try to guess.
As an aside, if you end up doing more metaprogramming, you'll find having template, non-type and type template arguments to be a real pain.
One approach is to turn all 3 into types.
template<template<class...>class Z>
struct ztemplate_t {
template<class...Ts> using apply=Z<Ts...>;
};
// C++17
template<auto x>
using zvalue_t = std::integral_constant< std::decay_t<decltype(x)>, x >;
// C++11
template<std::size_t x>
using zsize_t = std::integral_constant< std::size_t, x >;
Then we can write templates like apply that take a ztemplate as the first argument and apply it to the rest of the arguments, then zapply which is ztemplate<apply>.
Once that heavy lifting is done, TypedCollection<T> becomes partial_apply_t< zMyCollection_t, T>.
Another is to turn all 3 into constexpr values and do constexpr value-style metaprogramming.
Under this, we end up with type_t< decltype(zpartial_apply( zMyCollection, tag<T> ))>.
But for small one-off libraries, both of these are overkill.

unable to determine the template type even it is passed in [duplicate]

This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 7 years ago.
I have the following code:
template <typename T>
struct Data {
struct Embed
{
T t;
};
};
struct Functor {
template <typename T>
void foo( typename Data<T>::Embed & e) {}
};
template <typename T, typename F>
struct Caller
{
F f;
template <typename T>
void invoke() {
typename Data<T>::Embed e;
f.foo<T>(e); //compiler error pointed this line
}
};
Then I specialized the template as:
Caller<int, Functor> c;
c.invoke();
compiler error is : error: expected primary-expression before '>' in f.foo<T>(e); line. It seems compiler suddenly doesn't know what T is even it is specified in the template declaration on the function.
Take out the explicit specified T in foo.invoke(e) line will result could not deduce template parameter 'T'
How do I fix this? (I still want to keep the functionality that Caller can have generic functor and functor's function can be templated).
You are using:
template <typename T>
void invoke() {
typename Data<T>::Embed e;
f.foo<T>(e); //compiler error pointed this line
}
inside Caller even though T is one of the parameters of Caller. Remove the line
template <typename T>
and use just:
void invoke() {
typename Data<T>::Embed e;
// f.foo<T>(e); //compiler error pointed this line
f.template foo<T>(e); // Need the template keyword here.
}
However, as #Nawaz pointed out in a comment, that changes the semantics of invoke. If T in invoke was meant to be different than the T used to instantiate Caller, then it will be better to use a different name, say U.
The problem is that f is of type F which is template parameter, f.foo is a dependent name and which happens to be a function template. So you've to use template in a very weird way:
f.template foo<T>(e);
For further explantion, see these:
short explanation
long explanation
Also, I'd advise you to use U as template parameter for the function template invoke if at all it needs to be a template, else you can make it a normal function (i.e if the T of invoke is ought to be same as T of the enclosing class template).
Hope that helps.

"Transparency" of a template template argument (missing template argument) [duplicate]

This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 8 years ago.
To put it somewhat vaguely, from the snippet (tt.cc) below it seems to me as if the template template notion lacked some kind of a "transparency". While I don't seem to fathom what other template argument should A::f() be provided (besides the template template one), I might as well be just missing some banality here.
template <class T>
class A {
public:
template< template<class> class U >
void f( int i ) {
// ...
}
};
template< class T, template<class> class U >
class B {
public:
void f( int i ) {
A<T> a;
a.f<U>( i );
}
};
int main() {
return 0;
}
The error message it provides is:
g++ ./tt.cc -o tt
./tt.cc: In member function ‘void B<T, U>::f(int)’:
./tt.cc:17:10: error: missing template arguments before ‘>’ token
a.f<U>( i );
^
Compilation exited abnormally with code 1
Any ideas greatly appreciated.
What you are seeing is the compiler interpreting the > token inside f<U> as the inequality operator. You need to add .template to let the compiler know you mean a template argument.
void f( int i ) {
A<T> a;
a.template f<U>( i );
}
Live Example.
See also Where and why do I have to put the “template” and “typename” keywords?.

Function template parameter compilation error [duplicate]

This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 9 years ago.
I'm trying to do something like this:
#include <iostream>
#include <array>
using namespace std;
template <size_t A>
class Test {
public:
typedef array<int, A> TestType;
};
template <size_t A>
void foo(Test<A>::TestType t) {
cout << "test\n";
}
int main() {
Test<5>::TestType q;
foo(q);
return 0;
}
but foo doesn't compile. In gcc I get
prog.cpp:12:19: error: variable or field ‘foo’ declared void
void foo(Test<A>::TestType t) {
^
prog.cpp:12:28: error: expected ‘)’ before ‘t’
void foo(Test<A>::TestType t) {
while in Visual Studio 2010 I get
error C2975: 'Test' : invalid template argument for 'A', expected compile-time constant expression
I don't understand what I am doing wrong, as A is a compile-time constant. What should I change?
If you would add typename like this:
template <size_t A>
void foo(typename Test<A>::TestType t) {
cout << "test\n";
}
the only effect is a better error message. The problem is that you still can not deduce template parameters like that.
When you declare q
Test<5>::TestType q;
q's type is std::array<int,5> and the compiler doesn't know how this type was connected to Test<5>. In the call to foo(q) it would need a much deeper analysis of the code which is not standardized to figure out that there is only one possible match for A. You need to call
foo<5>(q);
to specify it explicitly or change the definition of foo:
template <size_t A>
void foo(std::array<int,A> t) {
cout << "test\n";
}